Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
parkpow
GitHub Repository: parkpow/deep-license-plate-recognition
Path: blob/master/cpp/linux/json/jsoncpp.cpp
644 views
1
/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/).
2
/// It is intended to be used with #include "json/json.h"
3
4
// //////////////////////////////////////////////////////////////////////
5
// Beginning of content of file: LICENSE
6
// //////////////////////////////////////////////////////////////////////
7
8
/*
9
The JsonCpp library's source code, including accompanying documentation,
10
tests and demonstration applications, are licensed under the following
11
conditions...
12
13
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
14
jurisdictions which recognize such a disclaimer. In such jurisdictions,
15
this software is released into the Public Domain.
16
17
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
18
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
19
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
20
21
In jurisdictions which recognize Public Domain property, the user of this
22
software may choose to accept it either as 1) Public Domain, 2) under the
23
conditions of the MIT License (see below), or 3) under the terms of dual
24
Public Domain/MIT License conditions described here, as they choose.
25
26
The MIT License is about as close to Public Domain as a license can get, and is
27
described in clear, concise terms at:
28
29
http://en.wikipedia.org/wiki/MIT_License
30
31
The full text of the MIT License follows:
32
33
========================================================================
34
Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
35
36
Permission is hereby granted, free of charge, to any person
37
obtaining a copy of this software and associated documentation
38
files (the "Software"), to deal in the Software without
39
restriction, including without limitation the rights to use, copy,
40
modify, merge, publish, distribute, sublicense, and/or sell copies
41
of the Software, and to permit persons to whom the Software is
42
furnished to do so, subject to the following conditions:
43
44
The above copyright notice and this permission notice shall be
45
included in all copies or substantial portions of the Software.
46
47
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
48
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
49
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
50
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
51
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
52
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
53
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
54
SOFTWARE.
55
========================================================================
56
(END LICENSE TEXT)
57
58
The MIT license is compatible with both the GPL and commercial
59
software, affording one all of the rights of Public Domain with the
60
minor nuisance of being required to keep the above copyright notice
61
and license text in the source code. Note also that by accepting the
62
Public Domain "license" you can re-license your copy using whatever
63
license you like.
64
65
*/
66
67
// //////////////////////////////////////////////////////////////////////
68
// End of content of file: LICENSE
69
// //////////////////////////////////////////////////////////////////////
70
71
72
73
74
75
76
#include "json/json.h"
77
78
#ifndef JSON_IS_AMALGAMATION
79
#error "Compile with -I PATH_TO_JSON_DIRECTORY"
80
#endif
81
82
83
// //////////////////////////////////////////////////////////////////////
84
// Beginning of content of file: src/lib_json/json_tool.h
85
// //////////////////////////////////////////////////////////////////////
86
87
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
88
// Distributed under MIT license, or public domain if desired and
89
// recognized in your jurisdiction.
90
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
91
92
#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
93
#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
94
95
#if !defined(JSON_IS_AMALGAMATION)
96
#include <json/config.h>
97
#endif
98
99
// Also support old flag NO_LOCALE_SUPPORT
100
#ifdef NO_LOCALE_SUPPORT
101
#define JSONCPP_NO_LOCALE_SUPPORT
102
#endif
103
104
#ifndef JSONCPP_NO_LOCALE_SUPPORT
105
#include <clocale>
106
#endif
107
108
/* This header provides common string manipulation support, such as UTF-8,
109
* portable conversion from/to string...
110
*
111
* It is an internal header that must not be exposed.
112
*/
113
114
namespace Json {
115
static inline char getDecimalPoint() {
116
#ifdef JSONCPP_NO_LOCALE_SUPPORT
117
return '\0';
118
#else
119
struct lconv* lc = localeconv();
120
return lc ? *(lc->decimal_point) : '\0';
121
#endif
122
}
123
124
/// Converts a unicode code-point to UTF-8.
125
static inline String codePointToUTF8(unsigned int cp) {
126
String result;
127
128
// based on description from http://en.wikipedia.org/wiki/UTF-8
129
130
if (cp <= 0x7f) {
131
result.resize(1);
132
result[0] = static_cast<char>(cp);
133
} else if (cp <= 0x7FF) {
134
result.resize(2);
135
result[1] = static_cast<char>(0x80 | (0x3f & cp));
136
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
137
} else if (cp <= 0xFFFF) {
138
result.resize(3);
139
result[2] = static_cast<char>(0x80 | (0x3f & cp));
140
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
141
result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
142
} else if (cp <= 0x10FFFF) {
143
result.resize(4);
144
result[3] = static_cast<char>(0x80 | (0x3f & cp));
145
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
146
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
147
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
148
}
149
150
return result;
151
}
152
153
enum {
154
/// Constant that specify the size of the buffer that must be passed to
155
/// uintToString.
156
uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
157
};
158
159
// Defines a char buffer for use with uintToString().
160
typedef char UIntToStringBuffer[uintToStringBufferSize];
161
162
/** Converts an unsigned integer to string.
163
* @param value Unsigned integer to convert to string
164
* @param current Input/Output string buffer.
165
* Must have at least uintToStringBufferSize chars free.
166
*/
167
static inline void uintToString(LargestUInt value, char*& current) {
168
*--current = 0;
169
do {
170
*--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));
171
value /= 10;
172
} while (value != 0);
173
}
174
175
/** Change ',' to '.' everywhere in buffer.
176
*
177
* We had a sophisticated way, but it did not work in WinCE.
178
* @see https://github.com/open-source-parsers/jsoncpp/pull/9
179
*/
180
template <typename Iter> Iter fixNumericLocale(Iter begin, Iter end) {
181
for (; begin != end; ++begin) {
182
if (*begin == ',') {
183
*begin = '.';
184
}
185
}
186
return begin;
187
}
188
189
template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
190
char decimalPoint = getDecimalPoint();
191
if (decimalPoint == '\0' || decimalPoint == '.') {
192
return;
193
}
194
for (; begin != end; ++begin) {
195
if (*begin == '.') {
196
*begin = decimalPoint;
197
}
198
}
199
}
200
201
/**
202
* Return iterator that would be the new end of the range [begin,end), if we
203
* were to delete zeros in the end of string, but not the last zero before '.'.
204
*/
205
template <typename Iter> Iter fixZerosInTheEnd(Iter begin, Iter end) {
206
for (; begin != end; --end) {
207
if (*(end - 1) != '0') {
208
return end;
209
}
210
// Don't delete the last zero before the decimal point.
211
if (begin != (end - 1) && *(end - 2) == '.') {
212
return end;
213
}
214
}
215
return end;
216
}
217
218
} // namespace Json
219
220
#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
221
222
// //////////////////////////////////////////////////////////////////////
223
// End of content of file: src/lib_json/json_tool.h
224
// //////////////////////////////////////////////////////////////////////
225
226
227
228
229
230
231
// //////////////////////////////////////////////////////////////////////
232
// Beginning of content of file: src/lib_json/json_reader.cpp
233
// //////////////////////////////////////////////////////////////////////
234
235
// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors
236
// Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
237
// Distributed under MIT license, or public domain if desired and
238
// recognized in your jurisdiction.
239
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
240
241
#if !defined(JSON_IS_AMALGAMATION)
242
#include "json_tool.h"
243
#include <json/assertions.h>
244
#include <json/reader.h>
245
#include <json/value.h>
246
#endif // if !defined(JSON_IS_AMALGAMATION)
247
#include <cassert>
248
#include <cstring>
249
#include <istream>
250
#include <limits>
251
#include <memory>
252
#include <set>
253
#include <sstream>
254
#include <utility>
255
256
#include <cstdio>
257
#if __cplusplus >= 201103L
258
259
#if !defined(sscanf)
260
#define sscanf std::sscanf
261
#endif
262
263
#endif //__cplusplus
264
265
#if defined(_MSC_VER)
266
#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
267
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
268
#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
269
#endif //_MSC_VER
270
271
#if defined(_MSC_VER)
272
// Disable warning about strdup being deprecated.
273
#pragma warning(disable : 4996)
274
#endif
275
276
// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
277
// time to change the stack limit
278
#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
279
#define JSONCPP_DEPRECATED_STACK_LIMIT 1000
280
#endif
281
282
static size_t const stackLimit_g =
283
JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
284
285
namespace Json {
286
287
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
288
typedef std::unique_ptr<CharReader> CharReaderPtr;
289
#else
290
typedef std::auto_ptr<CharReader> CharReaderPtr;
291
#endif
292
293
// Implementation of class Features
294
// ////////////////////////////////
295
296
Features::Features() = default;
297
298
Features Features::all() { return {}; }
299
300
Features Features::strictMode() {
301
Features features;
302
features.allowComments_ = false;
303
features.strictRoot_ = true;
304
features.allowDroppedNullPlaceholders_ = false;
305
features.allowNumericKeys_ = false;
306
return features;
307
}
308
309
// Implementation of class Reader
310
// ////////////////////////////////
311
312
bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
313
for (; begin < end; ++begin)
314
if (*begin == '\n' || *begin == '\r')
315
return true;
316
return false;
317
}
318
319
// Class Reader
320
// //////////////////////////////////////////////////////////////////
321
322
Reader::Reader()
323
: errors_(), document_(), commentsBefore_(), features_(Features::all()) {}
324
325
Reader::Reader(const Features& features)
326
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
327
lastValue_(), commentsBefore_(), features_(features), collectComments_() {
328
}
329
330
bool Reader::parse(const std::string& document,
331
Value& root,
332
bool collectComments) {
333
document_.assign(document.begin(), document.end());
334
const char* begin = document_.c_str();
335
const char* end = begin + document_.length();
336
return parse(begin, end, root, collectComments);
337
}
338
339
bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
340
// std::istream_iterator<char> begin(is);
341
// std::istream_iterator<char> end;
342
// Those would allow streamed input from a file, if parse() were a
343
// template function.
344
345
// Since String is reference-counted, this at least does not
346
// create an extra copy.
347
String doc;
348
std::getline(is, doc, (char)EOF);
349
return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
350
}
351
352
bool Reader::parse(const char* beginDoc,
353
const char* endDoc,
354
Value& root,
355
bool collectComments) {
356
if (!features_.allowComments_) {
357
collectComments = false;
358
}
359
360
begin_ = beginDoc;
361
end_ = endDoc;
362
collectComments_ = collectComments;
363
current_ = begin_;
364
lastValueEnd_ = nullptr;
365
lastValue_ = nullptr;
366
commentsBefore_.clear();
367
errors_.clear();
368
while (!nodes_.empty())
369
nodes_.pop();
370
nodes_.push(&root);
371
372
bool successful = readValue();
373
Token token;
374
skipCommentTokens(token);
375
if (collectComments_ && !commentsBefore_.empty())
376
root.setComment(commentsBefore_, commentAfter);
377
if (features_.strictRoot_) {
378
if (!root.isArray() && !root.isObject()) {
379
// Set error location to start of doc, ideally should be first token found
380
// in doc
381
token.type_ = tokenError;
382
token.start_ = beginDoc;
383
token.end_ = endDoc;
384
addError(
385
"A valid JSON document must be either an array or an object value.",
386
token);
387
return false;
388
}
389
}
390
return successful;
391
}
392
393
bool Reader::readValue() {
394
// readValue() may call itself only if it calls readObject() or ReadArray().
395
// These methods execute nodes_.push() just before and nodes_.pop)() just
396
// after calling readValue(). parse() executes one nodes_.push(), so > instead
397
// of >=.
398
if (nodes_.size() > stackLimit_g)
399
throwRuntimeError("Exceeded stackLimit in readValue().");
400
401
Token token;
402
skipCommentTokens(token);
403
bool successful = true;
404
405
if (collectComments_ && !commentsBefore_.empty()) {
406
currentValue().setComment(commentsBefore_, commentBefore);
407
commentsBefore_.clear();
408
}
409
410
switch (token.type_) {
411
case tokenObjectBegin:
412
successful = readObject(token);
413
currentValue().setOffsetLimit(current_ - begin_);
414
break;
415
case tokenArrayBegin:
416
successful = readArray(token);
417
currentValue().setOffsetLimit(current_ - begin_);
418
break;
419
case tokenNumber:
420
successful = decodeNumber(token);
421
break;
422
case tokenString:
423
successful = decodeString(token);
424
break;
425
case tokenTrue: {
426
Value v(true);
427
currentValue().swapPayload(v);
428
currentValue().setOffsetStart(token.start_ - begin_);
429
currentValue().setOffsetLimit(token.end_ - begin_);
430
} break;
431
case tokenFalse: {
432
Value v(false);
433
currentValue().swapPayload(v);
434
currentValue().setOffsetStart(token.start_ - begin_);
435
currentValue().setOffsetLimit(token.end_ - begin_);
436
} break;
437
case tokenNull: {
438
Value v;
439
currentValue().swapPayload(v);
440
currentValue().setOffsetStart(token.start_ - begin_);
441
currentValue().setOffsetLimit(token.end_ - begin_);
442
} break;
443
case tokenArraySeparator:
444
case tokenObjectEnd:
445
case tokenArrayEnd:
446
if (features_.allowDroppedNullPlaceholders_) {
447
// "Un-read" the current token and mark the current value as a null
448
// token.
449
current_--;
450
Value v;
451
currentValue().swapPayload(v);
452
currentValue().setOffsetStart(current_ - begin_ - 1);
453
currentValue().setOffsetLimit(current_ - begin_);
454
break;
455
} // Else, fall through...
456
default:
457
currentValue().setOffsetStart(token.start_ - begin_);
458
currentValue().setOffsetLimit(token.end_ - begin_);
459
return addError("Syntax error: value, object or array expected.", token);
460
}
461
462
if (collectComments_) {
463
lastValueEnd_ = current_;
464
lastValue_ = &currentValue();
465
}
466
467
return successful;
468
}
469
470
void Reader::skipCommentTokens(Token& token) {
471
if (features_.allowComments_) {
472
do {
473
readToken(token);
474
} while (token.type_ == tokenComment);
475
} else {
476
readToken(token);
477
}
478
}
479
480
bool Reader::readToken(Token& token) {
481
skipSpaces();
482
token.start_ = current_;
483
Char c = getNextChar();
484
bool ok = true;
485
switch (c) {
486
case '{':
487
token.type_ = tokenObjectBegin;
488
break;
489
case '}':
490
token.type_ = tokenObjectEnd;
491
break;
492
case '[':
493
token.type_ = tokenArrayBegin;
494
break;
495
case ']':
496
token.type_ = tokenArrayEnd;
497
break;
498
case '"':
499
token.type_ = tokenString;
500
ok = readString();
501
break;
502
case '/':
503
token.type_ = tokenComment;
504
ok = readComment();
505
break;
506
case '0':
507
case '1':
508
case '2':
509
case '3':
510
case '4':
511
case '5':
512
case '6':
513
case '7':
514
case '8':
515
case '9':
516
case '-':
517
token.type_ = tokenNumber;
518
readNumber();
519
break;
520
case 't':
521
token.type_ = tokenTrue;
522
ok = match("rue", 3);
523
break;
524
case 'f':
525
token.type_ = tokenFalse;
526
ok = match("alse", 4);
527
break;
528
case 'n':
529
token.type_ = tokenNull;
530
ok = match("ull", 3);
531
break;
532
case ',':
533
token.type_ = tokenArraySeparator;
534
break;
535
case ':':
536
token.type_ = tokenMemberSeparator;
537
break;
538
case 0:
539
token.type_ = tokenEndOfStream;
540
break;
541
default:
542
ok = false;
543
break;
544
}
545
if (!ok)
546
token.type_ = tokenError;
547
token.end_ = current_;
548
return true;
549
}
550
551
void Reader::skipSpaces() {
552
while (current_ != end_) {
553
Char c = *current_;
554
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
555
++current_;
556
else
557
break;
558
}
559
}
560
561
bool Reader::match(Location pattern, int patternLength) {
562
if (end_ - current_ < patternLength)
563
return false;
564
int index = patternLength;
565
while (index--)
566
if (current_[index] != pattern[index])
567
return false;
568
current_ += patternLength;
569
return true;
570
}
571
572
bool Reader::readComment() {
573
Location commentBegin = current_ - 1;
574
Char c = getNextChar();
575
bool successful = false;
576
if (c == '*')
577
successful = readCStyleComment();
578
else if (c == '/')
579
successful = readCppStyleComment();
580
if (!successful)
581
return false;
582
583
if (collectComments_) {
584
CommentPlacement placement = commentBefore;
585
if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
586
if (c != '*' || !containsNewLine(commentBegin, current_))
587
placement = commentAfterOnSameLine;
588
}
589
590
addComment(commentBegin, current_, placement);
591
}
592
return true;
593
}
594
595
String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
596
String normalized;
597
normalized.reserve(static_cast<size_t>(end - begin));
598
Reader::Location current = begin;
599
while (current != end) {
600
char c = *current++;
601
if (c == '\r') {
602
if (current != end && *current == '\n')
603
// convert dos EOL
604
++current;
605
// convert Mac EOL
606
normalized += '\n';
607
} else {
608
normalized += c;
609
}
610
}
611
return normalized;
612
}
613
614
void Reader::addComment(Location begin,
615
Location end,
616
CommentPlacement placement) {
617
assert(collectComments_);
618
const String& normalized = normalizeEOL(begin, end);
619
if (placement == commentAfterOnSameLine) {
620
assert(lastValue_ != nullptr);
621
lastValue_->setComment(normalized, placement);
622
} else {
623
commentsBefore_ += normalized;
624
}
625
}
626
627
bool Reader::readCStyleComment() {
628
while ((current_ + 1) < end_) {
629
Char c = getNextChar();
630
if (c == '*' && *current_ == '/')
631
break;
632
}
633
return getNextChar() == '/';
634
}
635
636
bool Reader::readCppStyleComment() {
637
while (current_ != end_) {
638
Char c = getNextChar();
639
if (c == '\n')
640
break;
641
if (c == '\r') {
642
// Consume DOS EOL. It will be normalized in addComment.
643
if (current_ != end_ && *current_ == '\n')
644
getNextChar();
645
// Break on Moc OS 9 EOL.
646
break;
647
}
648
}
649
return true;
650
}
651
652
void Reader::readNumber() {
653
const char* p = current_;
654
char c = '0'; // stopgap for already consumed character
655
// integral part
656
while (c >= '0' && c <= '9')
657
c = (current_ = p) < end_ ? *p++ : '\0';
658
// fractional part
659
if (c == '.') {
660
c = (current_ = p) < end_ ? *p++ : '\0';
661
while (c >= '0' && c <= '9')
662
c = (current_ = p) < end_ ? *p++ : '\0';
663
}
664
// exponential part
665
if (c == 'e' || c == 'E') {
666
c = (current_ = p) < end_ ? *p++ : '\0';
667
if (c == '+' || c == '-')
668
c = (current_ = p) < end_ ? *p++ : '\0';
669
while (c >= '0' && c <= '9')
670
c = (current_ = p) < end_ ? *p++ : '\0';
671
}
672
}
673
674
bool Reader::readString() {
675
Char c = '\0';
676
while (current_ != end_) {
677
c = getNextChar();
678
if (c == '\\')
679
getNextChar();
680
else if (c == '"')
681
break;
682
}
683
return c == '"';
684
}
685
686
bool Reader::readObject(Token& token) {
687
Token tokenName;
688
String name;
689
Value init(objectValue);
690
currentValue().swapPayload(init);
691
currentValue().setOffsetStart(token.start_ - begin_);
692
while (readToken(tokenName)) {
693
bool initialTokenOk = true;
694
while (tokenName.type_ == tokenComment && initialTokenOk)
695
initialTokenOk = readToken(tokenName);
696
if (!initialTokenOk)
697
break;
698
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
699
return true;
700
name.clear();
701
if (tokenName.type_ == tokenString) {
702
if (!decodeString(tokenName, name))
703
return recoverFromError(tokenObjectEnd);
704
} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
705
Value numberName;
706
if (!decodeNumber(tokenName, numberName))
707
return recoverFromError(tokenObjectEnd);
708
name = String(numberName.asCString());
709
} else {
710
break;
711
}
712
713
Token colon;
714
if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
715
return addErrorAndRecover("Missing ':' after object member name", colon,
716
tokenObjectEnd);
717
}
718
Value& value = currentValue()[name];
719
nodes_.push(&value);
720
bool ok = readValue();
721
nodes_.pop();
722
if (!ok) // error already set
723
return recoverFromError(tokenObjectEnd);
724
725
Token comma;
726
if (!readToken(comma) ||
727
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
728
comma.type_ != tokenComment)) {
729
return addErrorAndRecover("Missing ',' or '}' in object declaration",
730
comma, tokenObjectEnd);
731
}
732
bool finalizeTokenOk = true;
733
while (comma.type_ == tokenComment && finalizeTokenOk)
734
finalizeTokenOk = readToken(comma);
735
if (comma.type_ == tokenObjectEnd)
736
return true;
737
}
738
return addErrorAndRecover("Missing '}' or object member name", tokenName,
739
tokenObjectEnd);
740
}
741
742
bool Reader::readArray(Token& token) {
743
Value init(arrayValue);
744
currentValue().swapPayload(init);
745
currentValue().setOffsetStart(token.start_ - begin_);
746
skipSpaces();
747
if (current_ != end_ && *current_ == ']') // empty array
748
{
749
Token endArray;
750
readToken(endArray);
751
return true;
752
}
753
int index = 0;
754
for (;;) {
755
Value& value = currentValue()[index++];
756
nodes_.push(&value);
757
bool ok = readValue();
758
nodes_.pop();
759
if (!ok) // error already set
760
return recoverFromError(tokenArrayEnd);
761
762
Token currentToken;
763
// Accept Comment after last item in the array.
764
ok = readToken(currentToken);
765
while (currentToken.type_ == tokenComment && ok) {
766
ok = readToken(currentToken);
767
}
768
bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
769
currentToken.type_ != tokenArrayEnd);
770
if (!ok || badTokenType) {
771
return addErrorAndRecover("Missing ',' or ']' in array declaration",
772
currentToken, tokenArrayEnd);
773
}
774
if (currentToken.type_ == tokenArrayEnd)
775
break;
776
}
777
return true;
778
}
779
780
bool Reader::decodeNumber(Token& token) {
781
Value decoded;
782
if (!decodeNumber(token, decoded))
783
return false;
784
currentValue().swapPayload(decoded);
785
currentValue().setOffsetStart(token.start_ - begin_);
786
currentValue().setOffsetLimit(token.end_ - begin_);
787
return true;
788
}
789
790
bool Reader::decodeNumber(Token& token, Value& decoded) {
791
// Attempts to parse the number as an integer. If the number is
792
// larger than the maximum supported value of an integer then
793
// we decode the number as a double.
794
Location current = token.start_;
795
bool isNegative = *current == '-';
796
if (isNegative)
797
++current;
798
// TODO: Help the compiler do the div and mod at compile time or get rid of
799
// them.
800
Value::LargestUInt maxIntegerValue =
801
isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
802
: Value::maxLargestUInt;
803
Value::LargestUInt threshold = maxIntegerValue / 10;
804
Value::LargestUInt value = 0;
805
while (current < token.end_) {
806
Char c = *current++;
807
if (c < '0' || c > '9')
808
return decodeDouble(token, decoded);
809
auto digit(static_cast<Value::UInt>(c - '0'));
810
if (value >= threshold) {
811
// We've hit or exceeded the max value divided by 10 (rounded down). If
812
// a) we've only just touched the limit, b) this is the last digit, and
813
// c) it's small enough to fit in that rounding delta, we're okay.
814
// Otherwise treat this number as a double to avoid overflow.
815
if (value > threshold || current != token.end_ ||
816
digit > maxIntegerValue % 10) {
817
return decodeDouble(token, decoded);
818
}
819
}
820
value = value * 10 + digit;
821
}
822
if (isNegative && value == maxIntegerValue)
823
decoded = Value::minLargestInt;
824
else if (isNegative)
825
decoded = -Value::LargestInt(value);
826
else if (value <= Value::LargestUInt(Value::maxInt))
827
decoded = Value::LargestInt(value);
828
else
829
decoded = value;
830
return true;
831
}
832
833
bool Reader::decodeDouble(Token& token) {
834
Value decoded;
835
if (!decodeDouble(token, decoded))
836
return false;
837
currentValue().swapPayload(decoded);
838
currentValue().setOffsetStart(token.start_ - begin_);
839
currentValue().setOffsetLimit(token.end_ - begin_);
840
return true;
841
}
842
843
bool Reader::decodeDouble(Token& token, Value& decoded) {
844
double value = 0;
845
String buffer(token.start_, token.end_);
846
IStringStream is(buffer);
847
if (!(is >> value))
848
return addError(
849
"'" + String(token.start_, token.end_) + "' is not a number.", token);
850
decoded = value;
851
return true;
852
}
853
854
bool Reader::decodeString(Token& token) {
855
String decoded_string;
856
if (!decodeString(token, decoded_string))
857
return false;
858
Value decoded(decoded_string);
859
currentValue().swapPayload(decoded);
860
currentValue().setOffsetStart(token.start_ - begin_);
861
currentValue().setOffsetLimit(token.end_ - begin_);
862
return true;
863
}
864
865
bool Reader::decodeString(Token& token, String& decoded) {
866
decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
867
Location current = token.start_ + 1; // skip '"'
868
Location end = token.end_ - 1; // do not include '"'
869
while (current != end) {
870
Char c = *current++;
871
if (c == '"')
872
break;
873
else if (c == '\\') {
874
if (current == end)
875
return addError("Empty escape sequence in string", token, current);
876
Char escape = *current++;
877
switch (escape) {
878
case '"':
879
decoded += '"';
880
break;
881
case '/':
882
decoded += '/';
883
break;
884
case '\\':
885
decoded += '\\';
886
break;
887
case 'b':
888
decoded += '\b';
889
break;
890
case 'f':
891
decoded += '\f';
892
break;
893
case 'n':
894
decoded += '\n';
895
break;
896
case 'r':
897
decoded += '\r';
898
break;
899
case 't':
900
decoded += '\t';
901
break;
902
case 'u': {
903
unsigned int unicode;
904
if (!decodeUnicodeCodePoint(token, current, end, unicode))
905
return false;
906
decoded += codePointToUTF8(unicode);
907
} break;
908
default:
909
return addError("Bad escape sequence in string", token, current);
910
}
911
} else {
912
decoded += c;
913
}
914
}
915
return true;
916
}
917
918
bool Reader::decodeUnicodeCodePoint(Token& token,
919
Location& current,
920
Location end,
921
unsigned int& unicode) {
922
923
if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
924
return false;
925
if (unicode >= 0xD800 && unicode <= 0xDBFF) {
926
// surrogate pairs
927
if (end - current < 6)
928
return addError(
929
"additional six characters expected to parse unicode surrogate pair.",
930
token, current);
931
if (*(current++) == '\\' && *(current++) == 'u') {
932
unsigned int surrogatePair;
933
if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
934
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
935
} else
936
return false;
937
} else
938
return addError("expecting another \\u token to begin the second half of "
939
"a unicode surrogate pair",
940
token, current);
941
}
942
return true;
943
}
944
945
bool Reader::decodeUnicodeEscapeSequence(Token& token,
946
Location& current,
947
Location end,
948
unsigned int& ret_unicode) {
949
if (end - current < 4)
950
return addError(
951
"Bad unicode escape sequence in string: four digits expected.", token,
952
current);
953
int unicode = 0;
954
for (int index = 0; index < 4; ++index) {
955
Char c = *current++;
956
unicode *= 16;
957
if (c >= '0' && c <= '9')
958
unicode += c - '0';
959
else if (c >= 'a' && c <= 'f')
960
unicode += c - 'a' + 10;
961
else if (c >= 'A' && c <= 'F')
962
unicode += c - 'A' + 10;
963
else
964
return addError(
965
"Bad unicode escape sequence in string: hexadecimal digit expected.",
966
token, current);
967
}
968
ret_unicode = static_cast<unsigned int>(unicode);
969
return true;
970
}
971
972
bool Reader::addError(const String& message, Token& token, Location extra) {
973
ErrorInfo info;
974
info.token_ = token;
975
info.message_ = message;
976
info.extra_ = extra;
977
errors_.push_back(info);
978
return false;
979
}
980
981
bool Reader::recoverFromError(TokenType skipUntilToken) {
982
size_t const errorCount = errors_.size();
983
Token skip;
984
for (;;) {
985
if (!readToken(skip))
986
errors_.resize(errorCount); // discard errors caused by recovery
987
if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
988
break;
989
}
990
errors_.resize(errorCount);
991
return false;
992
}
993
994
bool Reader::addErrorAndRecover(const String& message,
995
Token& token,
996
TokenType skipUntilToken) {
997
addError(message, token);
998
return recoverFromError(skipUntilToken);
999
}
1000
1001
Value& Reader::currentValue() { return *(nodes_.top()); }
1002
1003
Reader::Char Reader::getNextChar() {
1004
if (current_ == end_)
1005
return 0;
1006
return *current_++;
1007
}
1008
1009
void Reader::getLocationLineAndColumn(Location location,
1010
int& line,
1011
int& column) const {
1012
Location current = begin_;
1013
Location lastLineStart = current;
1014
line = 0;
1015
while (current < location && current != end_) {
1016
Char c = *current++;
1017
if (c == '\r') {
1018
if (*current == '\n')
1019
++current;
1020
lastLineStart = current;
1021
++line;
1022
} else if (c == '\n') {
1023
lastLineStart = current;
1024
++line;
1025
}
1026
}
1027
// column & line start at 1
1028
column = int(location - lastLineStart) + 1;
1029
++line;
1030
}
1031
1032
String Reader::getLocationLineAndColumn(Location location) const {
1033
int line, column;
1034
getLocationLineAndColumn(location, line, column);
1035
char buffer[18 + 16 + 16 + 1];
1036
jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
1037
return buffer;
1038
}
1039
1040
// Deprecated. Preserved for backward compatibility
1041
String Reader::getFormatedErrorMessages() const {
1042
return getFormattedErrorMessages();
1043
}
1044
1045
String Reader::getFormattedErrorMessages() const {
1046
String formattedMessage;
1047
for (const auto& error : errors_) {
1048
formattedMessage +=
1049
"* " + getLocationLineAndColumn(error.token_.start_) + "\n";
1050
formattedMessage += " " + error.message_ + "\n";
1051
if (error.extra_)
1052
formattedMessage +=
1053
"See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
1054
}
1055
return formattedMessage;
1056
}
1057
1058
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
1059
std::vector<Reader::StructuredError> allErrors;
1060
for (const auto& error : errors_) {
1061
Reader::StructuredError structured;
1062
structured.offset_start = error.token_.start_ - begin_;
1063
structured.offset_limit = error.token_.end_ - begin_;
1064
structured.message = error.message_;
1065
allErrors.push_back(structured);
1066
}
1067
return allErrors;
1068
}
1069
1070
bool Reader::pushError(const Value& value, const String& message) {
1071
ptrdiff_t const length = end_ - begin_;
1072
if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
1073
return false;
1074
Token token;
1075
token.type_ = tokenError;
1076
token.start_ = begin_ + value.getOffsetStart();
1077
token.end_ = begin_ + value.getOffsetLimit();
1078
ErrorInfo info;
1079
info.token_ = token;
1080
info.message_ = message;
1081
info.extra_ = nullptr;
1082
errors_.push_back(info);
1083
return true;
1084
}
1085
1086
bool Reader::pushError(const Value& value,
1087
const String& message,
1088
const Value& extra) {
1089
ptrdiff_t const length = end_ - begin_;
1090
if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
1091
extra.getOffsetLimit() > length)
1092
return false;
1093
Token token;
1094
token.type_ = tokenError;
1095
token.start_ = begin_ + value.getOffsetStart();
1096
token.end_ = begin_ + value.getOffsetLimit();
1097
ErrorInfo info;
1098
info.token_ = token;
1099
info.message_ = message;
1100
info.extra_ = begin_ + extra.getOffsetStart();
1101
errors_.push_back(info);
1102
return true;
1103
}
1104
1105
bool Reader::good() const { return errors_.empty(); }
1106
1107
// Originally copied from the Features class (now deprecated), used internally
1108
// for features implementation.
1109
class OurFeatures {
1110
public:
1111
static OurFeatures all();
1112
bool allowComments_;
1113
bool strictRoot_;
1114
bool allowDroppedNullPlaceholders_;
1115
bool allowNumericKeys_;
1116
bool allowSingleQuotes_;
1117
bool failIfExtra_;
1118
bool rejectDupKeys_;
1119
bool allowSpecialFloats_;
1120
size_t stackLimit_;
1121
}; // OurFeatures
1122
1123
OurFeatures OurFeatures::all() { return {}; }
1124
1125
// Implementation of class Reader
1126
// ////////////////////////////////
1127
1128
// Originally copied from the Reader class (now deprecated), used internally
1129
// for implementing JSON reading.
1130
class OurReader {
1131
public:
1132
typedef char Char;
1133
typedef const Char* Location;
1134
struct StructuredError {
1135
ptrdiff_t offset_start;
1136
ptrdiff_t offset_limit;
1137
String message;
1138
};
1139
1140
OurReader(OurFeatures const& features);
1141
bool parse(const char* beginDoc,
1142
const char* endDoc,
1143
Value& root,
1144
bool collectComments = true);
1145
String getFormattedErrorMessages() const;
1146
std::vector<StructuredError> getStructuredErrors() const;
1147
bool pushError(const Value& value, const String& message);
1148
bool pushError(const Value& value, const String& message, const Value& extra);
1149
bool good() const;
1150
1151
private:
1152
OurReader(OurReader const&); // no impl
1153
void operator=(OurReader const&); // no impl
1154
1155
enum TokenType {
1156
tokenEndOfStream = 0,
1157
tokenObjectBegin,
1158
tokenObjectEnd,
1159
tokenArrayBegin,
1160
tokenArrayEnd,
1161
tokenString,
1162
tokenNumber,
1163
tokenTrue,
1164
tokenFalse,
1165
tokenNull,
1166
tokenNaN,
1167
tokenPosInf,
1168
tokenNegInf,
1169
tokenArraySeparator,
1170
tokenMemberSeparator,
1171
tokenComment,
1172
tokenError
1173
};
1174
1175
class Token {
1176
public:
1177
TokenType type_;
1178
Location start_;
1179
Location end_;
1180
};
1181
1182
class ErrorInfo {
1183
public:
1184
Token token_;
1185
String message_;
1186
Location extra_;
1187
};
1188
1189
typedef std::deque<ErrorInfo> Errors;
1190
1191
bool readToken(Token& token);
1192
void skipSpaces();
1193
bool match(Location pattern, int patternLength);
1194
bool readComment();
1195
bool readCStyleComment();
1196
bool readCppStyleComment();
1197
bool readString();
1198
bool readStringSingleQuote();
1199
bool readNumber(bool checkInf);
1200
bool readValue();
1201
bool readObject(Token& token);
1202
bool readArray(Token& token);
1203
bool decodeNumber(Token& token);
1204
bool decodeNumber(Token& token, Value& decoded);
1205
bool decodeString(Token& token);
1206
bool decodeString(Token& token, String& decoded);
1207
bool decodeDouble(Token& token);
1208
bool decodeDouble(Token& token, Value& decoded);
1209
bool decodeUnicodeCodePoint(Token& token,
1210
Location& current,
1211
Location end,
1212
unsigned int& unicode);
1213
bool decodeUnicodeEscapeSequence(Token& token,
1214
Location& current,
1215
Location end,
1216
unsigned int& unicode);
1217
bool addError(const String& message, Token& token, Location extra = nullptr);
1218
bool recoverFromError(TokenType skipUntilToken);
1219
bool addErrorAndRecover(const String& message,
1220
Token& token,
1221
TokenType skipUntilToken);
1222
void skipUntilSpace();
1223
Value& currentValue();
1224
Char getNextChar();
1225
void
1226
getLocationLineAndColumn(Location location, int& line, int& column) const;
1227
String getLocationLineAndColumn(Location location) const;
1228
void addComment(Location begin, Location end, CommentPlacement placement);
1229
void skipCommentTokens(Token& token);
1230
1231
static String normalizeEOL(Location begin, Location end);
1232
static bool containsNewLine(Location begin, Location end);
1233
1234
typedef std::stack<Value*> Nodes;
1235
Nodes nodes_;
1236
Errors errors_;
1237
String document_;
1238
Location begin_;
1239
Location end_;
1240
Location current_;
1241
Location lastValueEnd_;
1242
Value* lastValue_;
1243
String commentsBefore_;
1244
1245
OurFeatures const features_;
1246
bool collectComments_;
1247
}; // OurReader
1248
1249
// complete copy of Read impl, for OurReader
1250
1251
bool OurReader::containsNewLine(OurReader::Location begin,
1252
OurReader::Location end) {
1253
for (; begin < end; ++begin)
1254
if (*begin == '\n' || *begin == '\r')
1255
return true;
1256
return false;
1257
}
1258
1259
OurReader::OurReader(OurFeatures const& features)
1260
: errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
1261
lastValue_(), commentsBefore_(), features_(features), collectComments_() {
1262
}
1263
1264
bool OurReader::parse(const char* beginDoc,
1265
const char* endDoc,
1266
Value& root,
1267
bool collectComments) {
1268
if (!features_.allowComments_) {
1269
collectComments = false;
1270
}
1271
1272
begin_ = beginDoc;
1273
end_ = endDoc;
1274
collectComments_ = collectComments;
1275
current_ = begin_;
1276
lastValueEnd_ = nullptr;
1277
lastValue_ = nullptr;
1278
commentsBefore_.clear();
1279
errors_.clear();
1280
while (!nodes_.empty())
1281
nodes_.pop();
1282
nodes_.push(&root);
1283
1284
bool successful = readValue();
1285
nodes_.pop();
1286
Token token;
1287
skipCommentTokens(token);
1288
if (features_.failIfExtra_) {
1289
if ((features_.strictRoot_ || token.type_ != tokenError) &&
1290
token.type_ != tokenEndOfStream) {
1291
addError("Extra non-whitespace after JSON value.", token);
1292
return false;
1293
}
1294
}
1295
if (collectComments_ && !commentsBefore_.empty())
1296
root.setComment(commentsBefore_, commentAfter);
1297
if (features_.strictRoot_) {
1298
if (!root.isArray() && !root.isObject()) {
1299
// Set error location to start of doc, ideally should be first token found
1300
// in doc
1301
token.type_ = tokenError;
1302
token.start_ = beginDoc;
1303
token.end_ = endDoc;
1304
addError(
1305
"A valid JSON document must be either an array or an object value.",
1306
token);
1307
return false;
1308
}
1309
}
1310
return successful;
1311
}
1312
1313
bool OurReader::readValue() {
1314
// To preserve the old behaviour we cast size_t to int.
1315
if (nodes_.size() > features_.stackLimit_)
1316
throwRuntimeError("Exceeded stackLimit in readValue().");
1317
Token token;
1318
skipCommentTokens(token);
1319
bool successful = true;
1320
1321
if (collectComments_ && !commentsBefore_.empty()) {
1322
currentValue().setComment(commentsBefore_, commentBefore);
1323
commentsBefore_.clear();
1324
}
1325
1326
switch (token.type_) {
1327
case tokenObjectBegin:
1328
successful = readObject(token);
1329
currentValue().setOffsetLimit(current_ - begin_);
1330
break;
1331
case tokenArrayBegin:
1332
successful = readArray(token);
1333
currentValue().setOffsetLimit(current_ - begin_);
1334
break;
1335
case tokenNumber:
1336
successful = decodeNumber(token);
1337
break;
1338
case tokenString:
1339
successful = decodeString(token);
1340
break;
1341
case tokenTrue: {
1342
Value v(true);
1343
currentValue().swapPayload(v);
1344
currentValue().setOffsetStart(token.start_ - begin_);
1345
currentValue().setOffsetLimit(token.end_ - begin_);
1346
} break;
1347
case tokenFalse: {
1348
Value v(false);
1349
currentValue().swapPayload(v);
1350
currentValue().setOffsetStart(token.start_ - begin_);
1351
currentValue().setOffsetLimit(token.end_ - begin_);
1352
} break;
1353
case tokenNull: {
1354
Value v;
1355
currentValue().swapPayload(v);
1356
currentValue().setOffsetStart(token.start_ - begin_);
1357
currentValue().setOffsetLimit(token.end_ - begin_);
1358
} break;
1359
case tokenNaN: {
1360
Value v(std::numeric_limits<double>::quiet_NaN());
1361
currentValue().swapPayload(v);
1362
currentValue().setOffsetStart(token.start_ - begin_);
1363
currentValue().setOffsetLimit(token.end_ - begin_);
1364
} break;
1365
case tokenPosInf: {
1366
Value v(std::numeric_limits<double>::infinity());
1367
currentValue().swapPayload(v);
1368
currentValue().setOffsetStart(token.start_ - begin_);
1369
currentValue().setOffsetLimit(token.end_ - begin_);
1370
} break;
1371
case tokenNegInf: {
1372
Value v(-std::numeric_limits<double>::infinity());
1373
currentValue().swapPayload(v);
1374
currentValue().setOffsetStart(token.start_ - begin_);
1375
currentValue().setOffsetLimit(token.end_ - begin_);
1376
} break;
1377
case tokenArraySeparator:
1378
case tokenObjectEnd:
1379
case tokenArrayEnd:
1380
if (features_.allowDroppedNullPlaceholders_) {
1381
// "Un-read" the current token and mark the current value as a null
1382
// token.
1383
current_--;
1384
Value v;
1385
currentValue().swapPayload(v);
1386
currentValue().setOffsetStart(current_ - begin_ - 1);
1387
currentValue().setOffsetLimit(current_ - begin_);
1388
break;
1389
} // else, fall through ...
1390
default:
1391
currentValue().setOffsetStart(token.start_ - begin_);
1392
currentValue().setOffsetLimit(token.end_ - begin_);
1393
return addError("Syntax error: value, object or array expected.", token);
1394
}
1395
1396
if (collectComments_) {
1397
lastValueEnd_ = current_;
1398
lastValue_ = &currentValue();
1399
}
1400
1401
return successful;
1402
}
1403
1404
void OurReader::skipCommentTokens(Token& token) {
1405
if (features_.allowComments_) {
1406
do {
1407
readToken(token);
1408
} while (token.type_ == tokenComment);
1409
} else {
1410
readToken(token);
1411
}
1412
}
1413
1414
bool OurReader::readToken(Token& token) {
1415
skipSpaces();
1416
token.start_ = current_;
1417
Char c = getNextChar();
1418
bool ok = true;
1419
switch (c) {
1420
case '{':
1421
token.type_ = tokenObjectBegin;
1422
break;
1423
case '}':
1424
token.type_ = tokenObjectEnd;
1425
break;
1426
case '[':
1427
token.type_ = tokenArrayBegin;
1428
break;
1429
case ']':
1430
token.type_ = tokenArrayEnd;
1431
break;
1432
case '"':
1433
token.type_ = tokenString;
1434
ok = readString();
1435
break;
1436
case '\'':
1437
if (features_.allowSingleQuotes_) {
1438
token.type_ = tokenString;
1439
ok = readStringSingleQuote();
1440
break;
1441
} // else fall through
1442
case '/':
1443
token.type_ = tokenComment;
1444
ok = readComment();
1445
break;
1446
case '0':
1447
case '1':
1448
case '2':
1449
case '3':
1450
case '4':
1451
case '5':
1452
case '6':
1453
case '7':
1454
case '8':
1455
case '9':
1456
token.type_ = tokenNumber;
1457
readNumber(false);
1458
break;
1459
case '-':
1460
if (readNumber(true)) {
1461
token.type_ = tokenNumber;
1462
} else {
1463
token.type_ = tokenNegInf;
1464
ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1465
}
1466
break;
1467
case 't':
1468
token.type_ = tokenTrue;
1469
ok = match("rue", 3);
1470
break;
1471
case 'f':
1472
token.type_ = tokenFalse;
1473
ok = match("alse", 4);
1474
break;
1475
case 'n':
1476
token.type_ = tokenNull;
1477
ok = match("ull", 3);
1478
break;
1479
case 'N':
1480
if (features_.allowSpecialFloats_) {
1481
token.type_ = tokenNaN;
1482
ok = match("aN", 2);
1483
} else {
1484
ok = false;
1485
}
1486
break;
1487
case 'I':
1488
if (features_.allowSpecialFloats_) {
1489
token.type_ = tokenPosInf;
1490
ok = match("nfinity", 7);
1491
} else {
1492
ok = false;
1493
}
1494
break;
1495
case ',':
1496
token.type_ = tokenArraySeparator;
1497
break;
1498
case ':':
1499
token.type_ = tokenMemberSeparator;
1500
break;
1501
case 0:
1502
token.type_ = tokenEndOfStream;
1503
break;
1504
default:
1505
ok = false;
1506
break;
1507
}
1508
if (!ok)
1509
token.type_ = tokenError;
1510
token.end_ = current_;
1511
return true;
1512
}
1513
1514
void OurReader::skipSpaces() {
1515
while (current_ != end_) {
1516
Char c = *current_;
1517
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1518
++current_;
1519
else
1520
break;
1521
}
1522
}
1523
1524
bool OurReader::match(Location pattern, int patternLength) {
1525
if (end_ - current_ < patternLength)
1526
return false;
1527
int index = patternLength;
1528
while (index--)
1529
if (current_[index] != pattern[index])
1530
return false;
1531
current_ += patternLength;
1532
return true;
1533
}
1534
1535
bool OurReader::readComment() {
1536
Location commentBegin = current_ - 1;
1537
Char c = getNextChar();
1538
bool successful = false;
1539
if (c == '*')
1540
successful = readCStyleComment();
1541
else if (c == '/')
1542
successful = readCppStyleComment();
1543
if (!successful)
1544
return false;
1545
1546
if (collectComments_) {
1547
CommentPlacement placement = commentBefore;
1548
if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1549
if (c != '*' || !containsNewLine(commentBegin, current_))
1550
placement = commentAfterOnSameLine;
1551
}
1552
1553
addComment(commentBegin, current_, placement);
1554
}
1555
return true;
1556
}
1557
1558
String OurReader::normalizeEOL(OurReader::Location begin,
1559
OurReader::Location end) {
1560
String normalized;
1561
normalized.reserve(static_cast<size_t>(end - begin));
1562
OurReader::Location current = begin;
1563
while (current != end) {
1564
char c = *current++;
1565
if (c == '\r') {
1566
if (current != end && *current == '\n')
1567
// convert dos EOL
1568
++current;
1569
// convert Mac EOL
1570
normalized += '\n';
1571
} else {
1572
normalized += c;
1573
}
1574
}
1575
return normalized;
1576
}
1577
1578
void OurReader::addComment(Location begin,
1579
Location end,
1580
CommentPlacement placement) {
1581
assert(collectComments_);
1582
const String& normalized = normalizeEOL(begin, end);
1583
if (placement == commentAfterOnSameLine) {
1584
assert(lastValue_ != nullptr);
1585
lastValue_->setComment(normalized, placement);
1586
} else {
1587
commentsBefore_ += normalized;
1588
}
1589
}
1590
1591
bool OurReader::readCStyleComment() {
1592
while ((current_ + 1) < end_) {
1593
Char c = getNextChar();
1594
if (c == '*' && *current_ == '/')
1595
break;
1596
}
1597
return getNextChar() == '/';
1598
}
1599
1600
bool OurReader::readCppStyleComment() {
1601
while (current_ != end_) {
1602
Char c = getNextChar();
1603
if (c == '\n')
1604
break;
1605
if (c == '\r') {
1606
// Consume DOS EOL. It will be normalized in addComment.
1607
if (current_ != end_ && *current_ == '\n')
1608
getNextChar();
1609
// Break on Moc OS 9 EOL.
1610
break;
1611
}
1612
}
1613
return true;
1614
}
1615
1616
bool OurReader::readNumber(bool checkInf) {
1617
const char* p = current_;
1618
if (checkInf && p != end_ && *p == 'I') {
1619
current_ = ++p;
1620
return false;
1621
}
1622
char c = '0'; // stopgap for already consumed character
1623
// integral part
1624
while (c >= '0' && c <= '9')
1625
c = (current_ = p) < end_ ? *p++ : '\0';
1626
// fractional part
1627
if (c == '.') {
1628
c = (current_ = p) < end_ ? *p++ : '\0';
1629
while (c >= '0' && c <= '9')
1630
c = (current_ = p) < end_ ? *p++ : '\0';
1631
}
1632
// exponential part
1633
if (c == 'e' || c == 'E') {
1634
c = (current_ = p) < end_ ? *p++ : '\0';
1635
if (c == '+' || c == '-')
1636
c = (current_ = p) < end_ ? *p++ : '\0';
1637
while (c >= '0' && c <= '9')
1638
c = (current_ = p) < end_ ? *p++ : '\0';
1639
}
1640
return true;
1641
}
1642
bool OurReader::readString() {
1643
Char c = 0;
1644
while (current_ != end_) {
1645
c = getNextChar();
1646
if (c == '\\')
1647
getNextChar();
1648
else if (c == '"')
1649
break;
1650
}
1651
return c == '"';
1652
}
1653
1654
bool OurReader::readStringSingleQuote() {
1655
Char c = 0;
1656
while (current_ != end_) {
1657
c = getNextChar();
1658
if (c == '\\')
1659
getNextChar();
1660
else if (c == '\'')
1661
break;
1662
}
1663
return c == '\'';
1664
}
1665
1666
bool OurReader::readObject(Token& token) {
1667
Token tokenName;
1668
String name;
1669
Value init(objectValue);
1670
currentValue().swapPayload(init);
1671
currentValue().setOffsetStart(token.start_ - begin_);
1672
while (readToken(tokenName)) {
1673
bool initialTokenOk = true;
1674
while (tokenName.type_ == tokenComment && initialTokenOk)
1675
initialTokenOk = readToken(tokenName);
1676
if (!initialTokenOk)
1677
break;
1678
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
1679
return true;
1680
name.clear();
1681
if (tokenName.type_ == tokenString) {
1682
if (!decodeString(tokenName, name))
1683
return recoverFromError(tokenObjectEnd);
1684
} else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1685
Value numberName;
1686
if (!decodeNumber(tokenName, numberName))
1687
return recoverFromError(tokenObjectEnd);
1688
name = numberName.asString();
1689
} else {
1690
break;
1691
}
1692
if (name.length() >= (1U << 30))
1693
throwRuntimeError("keylength >= 2^30");
1694
if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1695
String msg = "Duplicate key: '" + name + "'";
1696
return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1697
}
1698
1699
Token colon;
1700
if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1701
return addErrorAndRecover("Missing ':' after object member name", colon,
1702
tokenObjectEnd);
1703
}
1704
Value& value = currentValue()[name];
1705
nodes_.push(&value);
1706
bool ok = readValue();
1707
nodes_.pop();
1708
if (!ok) // error already set
1709
return recoverFromError(tokenObjectEnd);
1710
1711
Token comma;
1712
if (!readToken(comma) ||
1713
(comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1714
comma.type_ != tokenComment)) {
1715
return addErrorAndRecover("Missing ',' or '}' in object declaration",
1716
comma, tokenObjectEnd);
1717
}
1718
bool finalizeTokenOk = true;
1719
while (comma.type_ == tokenComment && finalizeTokenOk)
1720
finalizeTokenOk = readToken(comma);
1721
if (comma.type_ == tokenObjectEnd)
1722
return true;
1723
}
1724
return addErrorAndRecover("Missing '}' or object member name", tokenName,
1725
tokenObjectEnd);
1726
}
1727
1728
bool OurReader::readArray(Token& token) {
1729
Value init(arrayValue);
1730
currentValue().swapPayload(init);
1731
currentValue().setOffsetStart(token.start_ - begin_);
1732
skipSpaces();
1733
if (current_ != end_ && *current_ == ']') // empty array
1734
{
1735
Token endArray;
1736
readToken(endArray);
1737
return true;
1738
}
1739
int index = 0;
1740
for (;;) {
1741
Value& value = currentValue()[index++];
1742
nodes_.push(&value);
1743
bool ok = readValue();
1744
nodes_.pop();
1745
if (!ok) // error already set
1746
return recoverFromError(tokenArrayEnd);
1747
1748
Token currentToken;
1749
// Accept Comment after last item in the array.
1750
ok = readToken(currentToken);
1751
while (currentToken.type_ == tokenComment && ok) {
1752
ok = readToken(currentToken);
1753
}
1754
bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
1755
currentToken.type_ != tokenArrayEnd);
1756
if (!ok || badTokenType) {
1757
return addErrorAndRecover("Missing ',' or ']' in array declaration",
1758
currentToken, tokenArrayEnd);
1759
}
1760
if (currentToken.type_ == tokenArrayEnd)
1761
break;
1762
}
1763
return true;
1764
}
1765
1766
bool OurReader::decodeNumber(Token& token) {
1767
Value decoded;
1768
if (!decodeNumber(token, decoded))
1769
return false;
1770
currentValue().swapPayload(decoded);
1771
currentValue().setOffsetStart(token.start_ - begin_);
1772
currentValue().setOffsetLimit(token.end_ - begin_);
1773
return true;
1774
}
1775
1776
bool OurReader::decodeNumber(Token& token, Value& decoded) {
1777
// Attempts to parse the number as an integer. If the number is
1778
// larger than the maximum supported value of an integer then
1779
// we decode the number as a double.
1780
Location current = token.start_;
1781
bool isNegative = *current == '-';
1782
if (isNegative)
1783
++current;
1784
1785
// TODO(issue #960): Change to constexpr
1786
static const auto positive_threshold = Value::maxLargestUInt / 10;
1787
static const auto positive_last_digit = Value::maxLargestUInt % 10;
1788
static const auto negative_threshold =
1789
Value::LargestUInt(Value::minLargestInt) / 10;
1790
static const auto negative_last_digit =
1791
Value::LargestUInt(Value::minLargestInt) % 10;
1792
1793
const auto threshold = isNegative ? negative_threshold : positive_threshold;
1794
const auto last_digit =
1795
isNegative ? negative_last_digit : positive_last_digit;
1796
1797
Value::LargestUInt value = 0;
1798
while (current < token.end_) {
1799
Char c = *current++;
1800
if (c < '0' || c > '9')
1801
return decodeDouble(token, decoded);
1802
1803
const auto digit(static_cast<Value::UInt>(c - '0'));
1804
if (value >= threshold) {
1805
// We've hit or exceeded the max value divided by 10 (rounded down). If
1806
// a) we've only just touched the limit, meaing value == threshold,
1807
// b) this is the last digit, or
1808
// c) it's small enough to fit in that rounding delta, we're okay.
1809
// Otherwise treat this number as a double to avoid overflow.
1810
if (value > threshold || current != token.end_ || digit > last_digit) {
1811
return decodeDouble(token, decoded);
1812
}
1813
}
1814
value = value * 10 + digit;
1815
}
1816
1817
if (isNegative)
1818
decoded = -Value::LargestInt(value);
1819
else if (value <= Value::LargestUInt(Value::maxLargestInt))
1820
decoded = Value::LargestInt(value);
1821
else
1822
decoded = value;
1823
1824
return true;
1825
}
1826
1827
bool OurReader::decodeDouble(Token& token) {
1828
Value decoded;
1829
if (!decodeDouble(token, decoded))
1830
return false;
1831
currentValue().swapPayload(decoded);
1832
currentValue().setOffsetStart(token.start_ - begin_);
1833
currentValue().setOffsetLimit(token.end_ - begin_);
1834
return true;
1835
}
1836
1837
bool OurReader::decodeDouble(Token& token, Value& decoded) {
1838
double value = 0;
1839
const int bufferSize = 32;
1840
int count;
1841
ptrdiff_t const length = token.end_ - token.start_;
1842
1843
// Sanity check to avoid buffer overflow exploits.
1844
if (length < 0) {
1845
return addError("Unable to parse token length", token);
1846
}
1847
auto const ulength = static_cast<size_t>(length);
1848
1849
// Avoid using a string constant for the format control string given to
1850
// sscanf, as this can cause hard to debug crashes on OS X. See here for more
1851
// info:
1852
//
1853
// http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
1854
char format[] = "%lf";
1855
1856
if (length <= bufferSize) {
1857
Char buffer[bufferSize + 1];
1858
memcpy(buffer, token.start_, ulength);
1859
buffer[length] = 0;
1860
fixNumericLocaleInput(buffer, buffer + length);
1861
count = sscanf(buffer, format, &value);
1862
} else {
1863
String buffer(token.start_, token.end_);
1864
count = sscanf(buffer.c_str(), format, &value);
1865
}
1866
1867
if (count != 1)
1868
return addError(
1869
"'" + String(token.start_, token.end_) + "' is not a number.", token);
1870
decoded = value;
1871
return true;
1872
}
1873
1874
bool OurReader::decodeString(Token& token) {
1875
String decoded_string;
1876
if (!decodeString(token, decoded_string))
1877
return false;
1878
Value decoded(decoded_string);
1879
currentValue().swapPayload(decoded);
1880
currentValue().setOffsetStart(token.start_ - begin_);
1881
currentValue().setOffsetLimit(token.end_ - begin_);
1882
return true;
1883
}
1884
1885
bool OurReader::decodeString(Token& token, String& decoded) {
1886
decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1887
Location current = token.start_ + 1; // skip '"'
1888
Location end = token.end_ - 1; // do not include '"'
1889
while (current != end) {
1890
Char c = *current++;
1891
if (c == '"')
1892
break;
1893
else if (c == '\\') {
1894
if (current == end)
1895
return addError("Empty escape sequence in string", token, current);
1896
Char escape = *current++;
1897
switch (escape) {
1898
case '"':
1899
decoded += '"';
1900
break;
1901
case '/':
1902
decoded += '/';
1903
break;
1904
case '\\':
1905
decoded += '\\';
1906
break;
1907
case 'b':
1908
decoded += '\b';
1909
break;
1910
case 'f':
1911
decoded += '\f';
1912
break;
1913
case 'n':
1914
decoded += '\n';
1915
break;
1916
case 'r':
1917
decoded += '\r';
1918
break;
1919
case 't':
1920
decoded += '\t';
1921
break;
1922
case 'u': {
1923
unsigned int unicode;
1924
if (!decodeUnicodeCodePoint(token, current, end, unicode))
1925
return false;
1926
decoded += codePointToUTF8(unicode);
1927
} break;
1928
default:
1929
return addError("Bad escape sequence in string", token, current);
1930
}
1931
} else {
1932
decoded += c;
1933
}
1934
}
1935
return true;
1936
}
1937
1938
bool OurReader::decodeUnicodeCodePoint(Token& token,
1939
Location& current,
1940
Location end,
1941
unsigned int& unicode) {
1942
1943
if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1944
return false;
1945
if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1946
// surrogate pairs
1947
if (end - current < 6)
1948
return addError(
1949
"additional six characters expected to parse unicode surrogate pair.",
1950
token, current);
1951
if (*(current++) == '\\' && *(current++) == 'u') {
1952
unsigned int surrogatePair;
1953
if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1954
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1955
} else
1956
return false;
1957
} else
1958
return addError("expecting another \\u token to begin the second half of "
1959
"a unicode surrogate pair",
1960
token, current);
1961
}
1962
return true;
1963
}
1964
1965
bool OurReader::decodeUnicodeEscapeSequence(Token& token,
1966
Location& current,
1967
Location end,
1968
unsigned int& ret_unicode) {
1969
if (end - current < 4)
1970
return addError(
1971
"Bad unicode escape sequence in string: four digits expected.", token,
1972
current);
1973
int unicode = 0;
1974
for (int index = 0; index < 4; ++index) {
1975
Char c = *current++;
1976
unicode *= 16;
1977
if (c >= '0' && c <= '9')
1978
unicode += c - '0';
1979
else if (c >= 'a' && c <= 'f')
1980
unicode += c - 'a' + 10;
1981
else if (c >= 'A' && c <= 'F')
1982
unicode += c - 'A' + 10;
1983
else
1984
return addError(
1985
"Bad unicode escape sequence in string: hexadecimal digit expected.",
1986
token, current);
1987
}
1988
ret_unicode = static_cast<unsigned int>(unicode);
1989
return true;
1990
}
1991
1992
bool OurReader::addError(const String& message, Token& token, Location extra) {
1993
ErrorInfo info;
1994
info.token_ = token;
1995
info.message_ = message;
1996
info.extra_ = extra;
1997
errors_.push_back(info);
1998
return false;
1999
}
2000
2001
bool OurReader::recoverFromError(TokenType skipUntilToken) {
2002
size_t errorCount = errors_.size();
2003
Token skip;
2004
for (;;) {
2005
if (!readToken(skip))
2006
errors_.resize(errorCount); // discard errors caused by recovery
2007
if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
2008
break;
2009
}
2010
errors_.resize(errorCount);
2011
return false;
2012
}
2013
2014
bool OurReader::addErrorAndRecover(const String& message,
2015
Token& token,
2016
TokenType skipUntilToken) {
2017
addError(message, token);
2018
return recoverFromError(skipUntilToken);
2019
}
2020
2021
Value& OurReader::currentValue() { return *(nodes_.top()); }
2022
2023
OurReader::Char OurReader::getNextChar() {
2024
if (current_ == end_)
2025
return 0;
2026
return *current_++;
2027
}
2028
2029
void OurReader::getLocationLineAndColumn(Location location,
2030
int& line,
2031
int& column) const {
2032
Location current = begin_;
2033
Location lastLineStart = current;
2034
line = 0;
2035
while (current < location && current != end_) {
2036
Char c = *current++;
2037
if (c == '\r') {
2038
if (*current == '\n')
2039
++current;
2040
lastLineStart = current;
2041
++line;
2042
} else if (c == '\n') {
2043
lastLineStart = current;
2044
++line;
2045
}
2046
}
2047
// column & line start at 1
2048
column = int(location - lastLineStart) + 1;
2049
++line;
2050
}
2051
2052
String OurReader::getLocationLineAndColumn(Location location) const {
2053
int line, column;
2054
getLocationLineAndColumn(location, line, column);
2055
char buffer[18 + 16 + 16 + 1];
2056
jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
2057
return buffer;
2058
}
2059
2060
String OurReader::getFormattedErrorMessages() const {
2061
String formattedMessage;
2062
for (const auto& error : errors_) {
2063
formattedMessage +=
2064
"* " + getLocationLineAndColumn(error.token_.start_) + "\n";
2065
formattedMessage += " " + error.message_ + "\n";
2066
if (error.extra_)
2067
formattedMessage +=
2068
"See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
2069
}
2070
return formattedMessage;
2071
}
2072
2073
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
2074
std::vector<OurReader::StructuredError> allErrors;
2075
for (const auto& error : errors_) {
2076
OurReader::StructuredError structured;
2077
structured.offset_start = error.token_.start_ - begin_;
2078
structured.offset_limit = error.token_.end_ - begin_;
2079
structured.message = error.message_;
2080
allErrors.push_back(structured);
2081
}
2082
return allErrors;
2083
}
2084
2085
bool OurReader::pushError(const Value& value, const String& message) {
2086
ptrdiff_t length = end_ - begin_;
2087
if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
2088
return false;
2089
Token token;
2090
token.type_ = tokenError;
2091
token.start_ = begin_ + value.getOffsetStart();
2092
token.end_ = begin_ + value.getOffsetLimit();
2093
ErrorInfo info;
2094
info.token_ = token;
2095
info.message_ = message;
2096
info.extra_ = nullptr;
2097
errors_.push_back(info);
2098
return true;
2099
}
2100
2101
bool OurReader::pushError(const Value& value,
2102
const String& message,
2103
const Value& extra) {
2104
ptrdiff_t length = end_ - begin_;
2105
if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
2106
extra.getOffsetLimit() > length)
2107
return false;
2108
Token token;
2109
token.type_ = tokenError;
2110
token.start_ = begin_ + value.getOffsetStart();
2111
token.end_ = begin_ + value.getOffsetLimit();
2112
ErrorInfo info;
2113
info.token_ = token;
2114
info.message_ = message;
2115
info.extra_ = begin_ + extra.getOffsetStart();
2116
errors_.push_back(info);
2117
return true;
2118
}
2119
2120
bool OurReader::good() const { return errors_.empty(); }
2121
2122
class OurCharReader : public CharReader {
2123
bool const collectComments_;
2124
OurReader reader_;
2125
2126
public:
2127
OurCharReader(bool collectComments, OurFeatures const& features)
2128
: collectComments_(collectComments), reader_(features) {}
2129
bool parse(char const* beginDoc,
2130
char const* endDoc,
2131
Value* root,
2132
String* errs) override {
2133
bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
2134
if (errs) {
2135
*errs = reader_.getFormattedErrorMessages();
2136
}
2137
return ok;
2138
}
2139
};
2140
2141
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
2142
CharReaderBuilder::~CharReaderBuilder() = default;
2143
CharReader* CharReaderBuilder::newCharReader() const {
2144
bool collectComments = settings_["collectComments"].asBool();
2145
OurFeatures features = OurFeatures::all();
2146
features.allowComments_ = settings_["allowComments"].asBool();
2147
features.strictRoot_ = settings_["strictRoot"].asBool();
2148
features.allowDroppedNullPlaceholders_ =
2149
settings_["allowDroppedNullPlaceholders"].asBool();
2150
features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
2151
features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
2152
2153
// Stack limit is always a size_t, so we get this as an unsigned int
2154
// regardless of it we have 64-bit integer support enabled.
2155
features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());
2156
features.failIfExtra_ = settings_["failIfExtra"].asBool();
2157
features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
2158
features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
2159
return new OurCharReader(collectComments, features);
2160
}
2161
static void getValidReaderKeys(std::set<String>* valid_keys) {
2162
valid_keys->clear();
2163
valid_keys->insert("collectComments");
2164
valid_keys->insert("allowComments");
2165
valid_keys->insert("strictRoot");
2166
valid_keys->insert("allowDroppedNullPlaceholders");
2167
valid_keys->insert("allowNumericKeys");
2168
valid_keys->insert("allowSingleQuotes");
2169
valid_keys->insert("stackLimit");
2170
valid_keys->insert("failIfExtra");
2171
valid_keys->insert("rejectDupKeys");
2172
valid_keys->insert("allowSpecialFloats");
2173
}
2174
bool CharReaderBuilder::validate(Json::Value* invalid) const {
2175
Json::Value my_invalid;
2176
if (!invalid)
2177
invalid = &my_invalid; // so we do not need to test for NULL
2178
Json::Value& inv = *invalid;
2179
std::set<String> valid_keys;
2180
getValidReaderKeys(&valid_keys);
2181
Value::Members keys = settings_.getMemberNames();
2182
size_t n = keys.size();
2183
for (size_t i = 0; i < n; ++i) {
2184
String const& key = keys[i];
2185
if (valid_keys.find(key) == valid_keys.end()) {
2186
inv[key] = settings_[key];
2187
}
2188
}
2189
return inv.empty();
2190
}
2191
Value& CharReaderBuilder::operator[](const String& key) {
2192
return settings_[key];
2193
}
2194
// static
2195
void CharReaderBuilder::strictMode(Json::Value* settings) {
2196
//! [CharReaderBuilderStrictMode]
2197
(*settings)["allowComments"] = false;
2198
(*settings)["strictRoot"] = true;
2199
(*settings)["allowDroppedNullPlaceholders"] = false;
2200
(*settings)["allowNumericKeys"] = false;
2201
(*settings)["allowSingleQuotes"] = false;
2202
(*settings)["stackLimit"] = 1000;
2203
(*settings)["failIfExtra"] = true;
2204
(*settings)["rejectDupKeys"] = true;
2205
(*settings)["allowSpecialFloats"] = false;
2206
//! [CharReaderBuilderStrictMode]
2207
}
2208
// static
2209
void CharReaderBuilder::setDefaults(Json::Value* settings) {
2210
//! [CharReaderBuilderDefaults]
2211
(*settings)["collectComments"] = true;
2212
(*settings)["allowComments"] = true;
2213
(*settings)["strictRoot"] = false;
2214
(*settings)["allowDroppedNullPlaceholders"] = false;
2215
(*settings)["allowNumericKeys"] = false;
2216
(*settings)["allowSingleQuotes"] = false;
2217
(*settings)["stackLimit"] = 1000;
2218
(*settings)["failIfExtra"] = false;
2219
(*settings)["rejectDupKeys"] = false;
2220
(*settings)["allowSpecialFloats"] = false;
2221
//! [CharReaderBuilderDefaults]
2222
}
2223
2224
//////////////////////////////////
2225
// global functions
2226
2227
bool parseFromStream(CharReader::Factory const& fact,
2228
IStream& sin,
2229
Value* root,
2230
String* errs) {
2231
OStringStream ssin;
2232
ssin << sin.rdbuf();
2233
String doc = ssin.str();
2234
char const* begin = doc.data();
2235
char const* end = begin + doc.size();
2236
// Note that we do not actually need a null-terminator.
2237
CharReaderPtr const reader(fact.newCharReader());
2238
return reader->parse(begin, end, root, errs);
2239
}
2240
2241
IStream& operator>>(IStream& sin, Value& root) {
2242
CharReaderBuilder b;
2243
String errs;
2244
bool ok = parseFromStream(b, sin, &root, &errs);
2245
if (!ok) {
2246
throwRuntimeError(errs);
2247
}
2248
return sin;
2249
}
2250
2251
} // namespace Json
2252
2253
// //////////////////////////////////////////////////////////////////////
2254
// End of content of file: src/lib_json/json_reader.cpp
2255
// //////////////////////////////////////////////////////////////////////
2256
2257
2258
2259
2260
2261
2262
// //////////////////////////////////////////////////////////////////////
2263
// Beginning of content of file: src/lib_json/json_valueiterator.inl
2264
// //////////////////////////////////////////////////////////////////////
2265
2266
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
2267
// Distributed under MIT license, or public domain if desired and
2268
// recognized in your jurisdiction.
2269
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2270
2271
// included by json_value.cpp
2272
2273
namespace Json {
2274
2275
// //////////////////////////////////////////////////////////////////
2276
// //////////////////////////////////////////////////////////////////
2277
// //////////////////////////////////////////////////////////////////
2278
// class ValueIteratorBase
2279
// //////////////////////////////////////////////////////////////////
2280
// //////////////////////////////////////////////////////////////////
2281
// //////////////////////////////////////////////////////////////////
2282
2283
ValueIteratorBase::ValueIteratorBase() : current_() {}
2284
2285
ValueIteratorBase::ValueIteratorBase(
2286
const Value::ObjectValues::iterator& current)
2287
: current_(current), isNull_(false) {}
2288
2289
Value& ValueIteratorBase::deref() const { return current_->second; }
2290
2291
void ValueIteratorBase::increment() { ++current_; }
2292
2293
void ValueIteratorBase::decrement() { --current_; }
2294
2295
ValueIteratorBase::difference_type
2296
ValueIteratorBase::computeDistance(const SelfType& other) const {
2297
#ifdef JSON_USE_CPPTL_SMALLMAP
2298
return other.current_ - current_;
2299
#else
2300
// Iterator for null value are initialized using the default
2301
// constructor, which initialize current_ to the default
2302
// std::map::iterator. As begin() and end() are two instance
2303
// of the default std::map::iterator, they can not be compared.
2304
// To allow this, we handle this comparison specifically.
2305
if (isNull_ && other.isNull_) {
2306
return 0;
2307
}
2308
2309
// Usage of std::distance is not portable (does not compile with Sun Studio 12
2310
// RogueWave STL,
2311
// which is the one used by default).
2312
// Using a portable hand-made version for non random iterator instead:
2313
// return difference_type( std::distance( current_, other.current_ ) );
2314
difference_type myDistance = 0;
2315
for (Value::ObjectValues::iterator it = current_; it != other.current_;
2316
++it) {
2317
++myDistance;
2318
}
2319
return myDistance;
2320
#endif
2321
}
2322
2323
bool ValueIteratorBase::isEqual(const SelfType& other) const {
2324
if (isNull_) {
2325
return other.isNull_;
2326
}
2327
return current_ == other.current_;
2328
}
2329
2330
void ValueIteratorBase::copy(const SelfType& other) {
2331
current_ = other.current_;
2332
isNull_ = other.isNull_;
2333
}
2334
2335
Value ValueIteratorBase::key() const {
2336
const Value::CZString czstring = (*current_).first;
2337
if (czstring.data()) {
2338
if (czstring.isStaticString())
2339
return Value(StaticString(czstring.data()));
2340
return Value(czstring.data(), czstring.data() + czstring.length());
2341
}
2342
return Value(czstring.index());
2343
}
2344
2345
UInt ValueIteratorBase::index() const {
2346
const Value::CZString czstring = (*current_).first;
2347
if (!czstring.data())
2348
return czstring.index();
2349
return Value::UInt(-1);
2350
}
2351
2352
String ValueIteratorBase::name() const {
2353
char const* keey;
2354
char const* end;
2355
keey = memberName(&end);
2356
if (!keey)
2357
return String();
2358
return String(keey, end);
2359
}
2360
2361
char const* ValueIteratorBase::memberName() const {
2362
const char* cname = (*current_).first.data();
2363
return cname ? cname : "";
2364
}
2365
2366
char const* ValueIteratorBase::memberName(char const** end) const {
2367
const char* cname = (*current_).first.data();
2368
if (!cname) {
2369
*end = nullptr;
2370
return nullptr;
2371
}
2372
*end = cname + (*current_).first.length();
2373
return cname;
2374
}
2375
2376
// //////////////////////////////////////////////////////////////////
2377
// //////////////////////////////////////////////////////////////////
2378
// //////////////////////////////////////////////////////////////////
2379
// class ValueConstIterator
2380
// //////////////////////////////////////////////////////////////////
2381
// //////////////////////////////////////////////////////////////////
2382
// //////////////////////////////////////////////////////////////////
2383
2384
ValueConstIterator::ValueConstIterator() = default;
2385
2386
ValueConstIterator::ValueConstIterator(
2387
const Value::ObjectValues::iterator& current)
2388
: ValueIteratorBase(current) {}
2389
2390
ValueConstIterator::ValueConstIterator(ValueIterator const& other)
2391
: ValueIteratorBase(other) {}
2392
2393
ValueConstIterator& ValueConstIterator::
2394
operator=(const ValueIteratorBase& other) {
2395
copy(other);
2396
return *this;
2397
}
2398
2399
// //////////////////////////////////////////////////////////////////
2400
// //////////////////////////////////////////////////////////////////
2401
// //////////////////////////////////////////////////////////////////
2402
// class ValueIterator
2403
// //////////////////////////////////////////////////////////////////
2404
// //////////////////////////////////////////////////////////////////
2405
// //////////////////////////////////////////////////////////////////
2406
2407
ValueIterator::ValueIterator() = default;
2408
2409
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
2410
: ValueIteratorBase(current) {}
2411
2412
ValueIterator::ValueIterator(const ValueConstIterator& other)
2413
: ValueIteratorBase(other) {
2414
throwRuntimeError("ConstIterator to Iterator should never be allowed.");
2415
}
2416
2417
ValueIterator::ValueIterator(const ValueIterator& other) = default;
2418
2419
ValueIterator& ValueIterator::operator=(const SelfType& other) {
2420
copy(other);
2421
return *this;
2422
}
2423
2424
} // namespace Json
2425
2426
// //////////////////////////////////////////////////////////////////////
2427
// End of content of file: src/lib_json/json_valueiterator.inl
2428
// //////////////////////////////////////////////////////////////////////
2429
2430
2431
2432
2433
2434
2435
// //////////////////////////////////////////////////////////////////////
2436
// Beginning of content of file: src/lib_json/json_value.cpp
2437
// //////////////////////////////////////////////////////////////////////
2438
2439
// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
2440
// Distributed under MIT license, or public domain if desired and
2441
// recognized in your jurisdiction.
2442
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
2443
2444
#if !defined(JSON_IS_AMALGAMATION)
2445
#include <json/assertions.h>
2446
#include <json/value.h>
2447
#include <json/writer.h>
2448
#endif // if !defined(JSON_IS_AMALGAMATION)
2449
#include <cassert>
2450
#include <cmath>
2451
#include <cstring>
2452
#include <sstream>
2453
#include <utility>
2454
#ifdef JSON_USE_CPPTL
2455
#include <cpptl/conststring.h>
2456
#endif
2457
#include <algorithm> // min()
2458
#include <cstddef> // size_t
2459
2460
// Provide implementation equivalent of std::snprintf for older _MSC compilers
2461
#if defined(_MSC_VER) && _MSC_VER < 1900
2462
#include <stdarg.h>
2463
static int msvc_pre1900_c99_vsnprintf(char* outBuf,
2464
size_t size,
2465
const char* format,
2466
va_list ap) {
2467
int count = -1;
2468
if (size != 0)
2469
count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
2470
if (count == -1)
2471
count = _vscprintf(format, ap);
2472
return count;
2473
}
2474
2475
int JSON_API msvc_pre1900_c99_snprintf(char* outBuf,
2476
size_t size,
2477
const char* format,
2478
...) {
2479
va_list ap;
2480
va_start(ap, format);
2481
const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);
2482
va_end(ap);
2483
return count;
2484
}
2485
#endif
2486
2487
// Disable warning C4702 : unreachable code
2488
#if defined(_MSC_VER)
2489
#pragma warning(disable : 4702)
2490
#endif
2491
2492
#define JSON_ASSERT_UNREACHABLE assert(false)
2493
2494
namespace Json {
2495
template <typename T>
2496
static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
2497
std::unique_ptr<T> r;
2498
if (p) {
2499
r = std::unique_ptr<T>(new T(*p));
2500
}
2501
return r;
2502
}
2503
2504
// This is a walkaround to avoid the static initialization of Value::null.
2505
// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
2506
// 8 (instead of 4) as a bit of future-proofing.
2507
#if defined(__ARMEL__)
2508
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
2509
#else
2510
#define ALIGNAS(byte_alignment)
2511
#endif
2512
2513
// static
2514
Value const& Value::nullSingleton() {
2515
static Value const nullStatic;
2516
return nullStatic;
2517
}
2518
2519
#if JSON_USE_NULLREF
2520
// for backwards compatibility, we'll leave these global references around, but
2521
// DO NOT use them in JSONCPP library code any more!
2522
// static
2523
Value const& Value::null = Value::nullSingleton();
2524
2525
// static
2526
Value const& Value::nullRef = Value::nullSingleton();
2527
#endif
2528
2529
const Int Value::minInt = Int(~(UInt(-1) / 2));
2530
const Int Value::maxInt = Int(UInt(-1) / 2);
2531
const UInt Value::maxUInt = UInt(-1);
2532
#if defined(JSON_HAS_INT64)
2533
const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
2534
const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
2535
const UInt64 Value::maxUInt64 = UInt64(-1);
2536
// The constant is hard-coded because some compiler have trouble
2537
// converting Value::maxUInt64 to a double correctly (AIX/xlC).
2538
// Assumes that UInt64 is a 64 bits integer.
2539
static const double maxUInt64AsDouble = 18446744073709551615.0;
2540
#endif // defined(JSON_HAS_INT64)
2541
const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
2542
const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
2543
const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
2544
2545
const UInt Value::defaultRealPrecision = 17;
2546
2547
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2548
template <typename T, typename U>
2549
static inline bool InRange(double d, T min, U max) {
2550
// The casts can lose precision, but we are looking only for
2551
// an approximate range. Might fail on edge cases though. ~cdunn
2552
// return d >= static_cast<double>(min) && d <= static_cast<double>(max);
2553
return d >= min && d <= max;
2554
}
2555
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2556
static inline double integerToDouble(Json::UInt64 value) {
2557
return static_cast<double>(Int64(value / 2)) * 2.0 +
2558
static_cast<double>(Int64(value & 1));
2559
}
2560
2561
template <typename T> static inline double integerToDouble(T value) {
2562
return static_cast<double>(value);
2563
}
2564
2565
template <typename T, typename U>
2566
static inline bool InRange(double d, T min, U max) {
2567
return d >= integerToDouble(min) && d <= integerToDouble(max);
2568
}
2569
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
2570
2571
/** Duplicates the specified string value.
2572
* @param value Pointer to the string to duplicate. Must be zero-terminated if
2573
* length is "unknown".
2574
* @param length Length of the value. if equals to unknown, then it will be
2575
* computed using strlen(value).
2576
* @return Pointer on the duplicate instance of string.
2577
*/
2578
static inline char* duplicateStringValue(const char* value, size_t length) {
2579
// Avoid an integer overflow in the call to malloc below by limiting length
2580
// to a sane value.
2581
if (length >= static_cast<size_t>(Value::maxInt))
2582
length = Value::maxInt - 1;
2583
2584
char* newString = static_cast<char*>(malloc(length + 1));
2585
if (newString == nullptr) {
2586
throwRuntimeError("in Json::Value::duplicateStringValue(): "
2587
"Failed to allocate string value buffer");
2588
}
2589
memcpy(newString, value, length);
2590
newString[length] = 0;
2591
return newString;
2592
}
2593
2594
/* Record the length as a prefix.
2595
*/
2596
static inline char* duplicateAndPrefixStringValue(const char* value,
2597
unsigned int length) {
2598
// Avoid an integer overflow in the call to malloc below by limiting length
2599
// to a sane value.
2600
JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -
2601
sizeof(unsigned) - 1U,
2602
"in Json::Value::duplicateAndPrefixStringValue(): "
2603
"length too big for prefixing");
2604
unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
2605
char* newString = static_cast<char*>(malloc(actualLength));
2606
if (newString == nullptr) {
2607
throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
2608
"Failed to allocate string value buffer");
2609
}
2610
*reinterpret_cast<unsigned*>(newString) = length;
2611
memcpy(newString + sizeof(unsigned), value, length);
2612
newString[actualLength - 1U] =
2613
0; // to avoid buffer over-run accidents by users later
2614
return newString;
2615
}
2616
inline static void decodePrefixedString(bool isPrefixed,
2617
char const* prefixed,
2618
unsigned* length,
2619
char const** value) {
2620
if (!isPrefixed) {
2621
*length = static_cast<unsigned>(strlen(prefixed));
2622
*value = prefixed;
2623
} else {
2624
*length = *reinterpret_cast<unsigned const*>(prefixed);
2625
*value = prefixed + sizeof(unsigned);
2626
}
2627
}
2628
/** Free the string duplicated by
2629
* duplicateStringValue()/duplicateAndPrefixStringValue().
2630
*/
2631
#if JSONCPP_USING_SECURE_MEMORY
2632
static inline void releasePrefixedStringValue(char* value) {
2633
unsigned length = 0;
2634
char const* valueDecoded;
2635
decodePrefixedString(true, value, &length, &valueDecoded);
2636
size_t const size = sizeof(unsigned) + length + 1U;
2637
memset(value, 0, size);
2638
free(value);
2639
}
2640
static inline void releaseStringValue(char* value, unsigned length) {
2641
// length==0 => we allocated the strings memory
2642
size_t size = (length == 0) ? strlen(value) : length;
2643
memset(value, 0, size);
2644
free(value);
2645
}
2646
#else // !JSONCPP_USING_SECURE_MEMORY
2647
static inline void releasePrefixedStringValue(char* value) { free(value); }
2648
static inline void releaseStringValue(char* value, unsigned) { free(value); }
2649
#endif // JSONCPP_USING_SECURE_MEMORY
2650
2651
} // namespace Json
2652
2653
// //////////////////////////////////////////////////////////////////
2654
// //////////////////////////////////////////////////////////////////
2655
// //////////////////////////////////////////////////////////////////
2656
// ValueInternals...
2657
// //////////////////////////////////////////////////////////////////
2658
// //////////////////////////////////////////////////////////////////
2659
// //////////////////////////////////////////////////////////////////
2660
#if !defined(JSON_IS_AMALGAMATION)
2661
2662
#include "json_valueiterator.inl"
2663
#endif // if !defined(JSON_IS_AMALGAMATION)
2664
2665
namespace Json {
2666
2667
#if JSON_USE_EXCEPTION
2668
Exception::Exception(String msg) : msg_(std::move(msg)) {}
2669
Exception::~Exception() JSONCPP_NOEXCEPT {}
2670
char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); }
2671
RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
2672
LogicError::LogicError(String const& msg) : Exception(msg) {}
2673
[[noreturn]] void throwRuntimeError(String const& msg) {
2674
throw RuntimeError(msg);
2675
}
2676
[[noreturn]] void throwLogicError(String const& msg) { throw LogicError(msg); }
2677
#else // !JSON_USE_EXCEPTION
2678
[[noreturn]] void throwRuntimeError(String const& msg) { abort(); }
2679
[[noreturn]] void throwLogicError(String const& msg) { abort(); }
2680
#endif
2681
2682
// //////////////////////////////////////////////////////////////////
2683
// //////////////////////////////////////////////////////////////////
2684
// //////////////////////////////////////////////////////////////////
2685
// class Value::CZString
2686
// //////////////////////////////////////////////////////////////////
2687
// //////////////////////////////////////////////////////////////////
2688
// //////////////////////////////////////////////////////////////////
2689
2690
// Notes: policy_ indicates if the string was allocated when
2691
// a string is stored.
2692
2693
Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}
2694
2695
Value::CZString::CZString(char const* str,
2696
unsigned length,
2697
DuplicationPolicy allocate)
2698
: cstr_(str) {
2699
// allocate != duplicate
2700
storage_.policy_ = allocate & 0x3;
2701
storage_.length_ = length & 0x3FFFFFFF;
2702
}
2703
2704
Value::CZString::CZString(const CZString& other) {
2705
cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
2706
? duplicateStringValue(other.cstr_, other.storage_.length_)
2707
: other.cstr_);
2708
storage_.policy_ =
2709
static_cast<unsigned>(
2710
other.cstr_
2711
? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
2712
noDuplication
2713
? noDuplication
2714
: duplicate)
2715
: static_cast<DuplicationPolicy>(other.storage_.policy_)) &
2716
3U;
2717
storage_.length_ = other.storage_.length_;
2718
}
2719
2720
Value::CZString::CZString(CZString&& other)
2721
: cstr_(other.cstr_), index_(other.index_) {
2722
other.cstr_ = nullptr;
2723
}
2724
2725
Value::CZString::~CZString() {
2726
if (cstr_ && storage_.policy_ == duplicate) {
2727
releaseStringValue(const_cast<char*>(cstr_),
2728
storage_.length_ + 1u); // +1 for null terminating
2729
// character for sake of
2730
// completeness but not actually
2731
// necessary
2732
}
2733
}
2734
2735
void Value::CZString::swap(CZString& other) {
2736
std::swap(cstr_, other.cstr_);
2737
std::swap(index_, other.index_);
2738
}
2739
2740
Value::CZString& Value::CZString::operator=(const CZString& other) {
2741
cstr_ = other.cstr_;
2742
index_ = other.index_;
2743
return *this;
2744
}
2745
2746
Value::CZString& Value::CZString::operator=(CZString&& other) {
2747
cstr_ = other.cstr_;
2748
index_ = other.index_;
2749
other.cstr_ = nullptr;
2750
return *this;
2751
}
2752
2753
bool Value::CZString::operator<(const CZString& other) const {
2754
if (!cstr_)
2755
return index_ < other.index_;
2756
// return strcmp(cstr_, other.cstr_) < 0;
2757
// Assume both are strings.
2758
unsigned this_len = this->storage_.length_;
2759
unsigned other_len = other.storage_.length_;
2760
unsigned min_len = std::min<unsigned>(this_len, other_len);
2761
JSON_ASSERT(this->cstr_ && other.cstr_);
2762
int comp = memcmp(this->cstr_, other.cstr_, min_len);
2763
if (comp < 0)
2764
return true;
2765
if (comp > 0)
2766
return false;
2767
return (this_len < other_len);
2768
}
2769
2770
bool Value::CZString::operator==(const CZString& other) const {
2771
if (!cstr_)
2772
return index_ == other.index_;
2773
// return strcmp(cstr_, other.cstr_) == 0;
2774
// Assume both are strings.
2775
unsigned this_len = this->storage_.length_;
2776
unsigned other_len = other.storage_.length_;
2777
if (this_len != other_len)
2778
return false;
2779
JSON_ASSERT(this->cstr_ && other.cstr_);
2780
int comp = memcmp(this->cstr_, other.cstr_, this_len);
2781
return comp == 0;
2782
}
2783
2784
ArrayIndex Value::CZString::index() const { return index_; }
2785
2786
// const char* Value::CZString::c_str() const { return cstr_; }
2787
const char* Value::CZString::data() const { return cstr_; }
2788
unsigned Value::CZString::length() const { return storage_.length_; }
2789
bool Value::CZString::isStaticString() const {
2790
return storage_.policy_ == noDuplication;
2791
}
2792
2793
// //////////////////////////////////////////////////////////////////
2794
// //////////////////////////////////////////////////////////////////
2795
// //////////////////////////////////////////////////////////////////
2796
// class Value::Value
2797
// //////////////////////////////////////////////////////////////////
2798
// //////////////////////////////////////////////////////////////////
2799
// //////////////////////////////////////////////////////////////////
2800
2801
/*! \internal Default constructor initialization must be equivalent to:
2802
* memset( this, 0, sizeof(Value) )
2803
* This optimization is used in ValueInternalMap fast allocator.
2804
*/
2805
Value::Value(ValueType type) {
2806
static char const emptyString[] = "";
2807
initBasic(type);
2808
switch (type) {
2809
case nullValue:
2810
break;
2811
case intValue:
2812
case uintValue:
2813
value_.int_ = 0;
2814
break;
2815
case realValue:
2816
value_.real_ = 0.0;
2817
break;
2818
case stringValue:
2819
// allocated_ == false, so this is safe.
2820
value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
2821
break;
2822
case arrayValue:
2823
case objectValue:
2824
value_.map_ = new ObjectValues();
2825
break;
2826
case booleanValue:
2827
value_.bool_ = false;
2828
break;
2829
default:
2830
JSON_ASSERT_UNREACHABLE;
2831
}
2832
}
2833
2834
Value::Value(Int value) {
2835
initBasic(intValue);
2836
value_.int_ = value;
2837
}
2838
2839
Value::Value(UInt value) {
2840
initBasic(uintValue);
2841
value_.uint_ = value;
2842
}
2843
#if defined(JSON_HAS_INT64)
2844
Value::Value(Int64 value) {
2845
initBasic(intValue);
2846
value_.int_ = value;
2847
}
2848
Value::Value(UInt64 value) {
2849
initBasic(uintValue);
2850
value_.uint_ = value;
2851
}
2852
#endif // defined(JSON_HAS_INT64)
2853
2854
Value::Value(double value) {
2855
initBasic(realValue);
2856
value_.real_ = value;
2857
}
2858
2859
Value::Value(const char* value) {
2860
initBasic(stringValue, true);
2861
JSON_ASSERT_MESSAGE(value != nullptr,
2862
"Null Value Passed to Value Constructor");
2863
value_.string_ = duplicateAndPrefixStringValue(
2864
value, static_cast<unsigned>(strlen(value)));
2865
}
2866
2867
Value::Value(const char* begin, const char* end) {
2868
initBasic(stringValue, true);
2869
value_.string_ =
2870
duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
2871
}
2872
2873
Value::Value(const String& value) {
2874
initBasic(stringValue, true);
2875
value_.string_ = duplicateAndPrefixStringValue(
2876
value.data(), static_cast<unsigned>(value.length()));
2877
}
2878
2879
Value::Value(const StaticString& value) {
2880
initBasic(stringValue);
2881
value_.string_ = const_cast<char*>(value.c_str());
2882
}
2883
2884
#ifdef JSON_USE_CPPTL
2885
Value::Value(const CppTL::ConstString& value) {
2886
initBasic(stringValue, true);
2887
value_.string_ = duplicateAndPrefixStringValue(
2888
value, static_cast<unsigned>(value.length()));
2889
}
2890
#endif
2891
2892
Value::Value(bool value) {
2893
initBasic(booleanValue);
2894
value_.bool_ = value;
2895
}
2896
2897
Value::Value(const Value& other) {
2898
dupPayload(other);
2899
dupMeta(other);
2900
}
2901
2902
Value::Value(Value&& other) {
2903
initBasic(nullValue);
2904
swap(other);
2905
}
2906
2907
Value::~Value() {
2908
releasePayload();
2909
value_.uint_ = 0;
2910
}
2911
2912
Value& Value::operator=(const Value& other) {
2913
Value(other).swap(*this);
2914
return *this;
2915
}
2916
2917
Value& Value::operator=(Value&& other) {
2918
other.swap(*this);
2919
return *this;
2920
}
2921
2922
void Value::swapPayload(Value& other) {
2923
std::swap(bits_, other.bits_);
2924
std::swap(value_, other.value_);
2925
}
2926
2927
void Value::copyPayload(const Value& other) {
2928
releasePayload();
2929
dupPayload(other);
2930
}
2931
2932
void Value::swap(Value& other) {
2933
swapPayload(other);
2934
std::swap(comments_, other.comments_);
2935
std::swap(start_, other.start_);
2936
std::swap(limit_, other.limit_);
2937
}
2938
2939
void Value::copy(const Value& other) {
2940
copyPayload(other);
2941
dupMeta(other);
2942
}
2943
2944
ValueType Value::type() const {
2945
return static_cast<ValueType>(bits_.value_type_);
2946
}
2947
2948
int Value::compare(const Value& other) const {
2949
if (*this < other)
2950
return -1;
2951
if (*this > other)
2952
return 1;
2953
return 0;
2954
}
2955
2956
bool Value::operator<(const Value& other) const {
2957
int typeDelta = type() - other.type();
2958
if (typeDelta)
2959
return typeDelta < 0 ? true : false;
2960
switch (type()) {
2961
case nullValue:
2962
return false;
2963
case intValue:
2964
return value_.int_ < other.value_.int_;
2965
case uintValue:
2966
return value_.uint_ < other.value_.uint_;
2967
case realValue:
2968
return value_.real_ < other.value_.real_;
2969
case booleanValue:
2970
return value_.bool_ < other.value_.bool_;
2971
case stringValue: {
2972
if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
2973
if (other.value_.string_)
2974
return true;
2975
else
2976
return false;
2977
}
2978
unsigned this_len;
2979
unsigned other_len;
2980
char const* this_str;
2981
char const* other_str;
2982
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
2983
&this_str);
2984
decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
2985
&other_str);
2986
unsigned min_len = std::min<unsigned>(this_len, other_len);
2987
JSON_ASSERT(this_str && other_str);
2988
int comp = memcmp(this_str, other_str, min_len);
2989
if (comp < 0)
2990
return true;
2991
if (comp > 0)
2992
return false;
2993
return (this_len < other_len);
2994
}
2995
case arrayValue:
2996
case objectValue: {
2997
int delta = int(value_.map_->size() - other.value_.map_->size());
2998
if (delta)
2999
return delta < 0;
3000
return (*value_.map_) < (*other.value_.map_);
3001
}
3002
default:
3003
JSON_ASSERT_UNREACHABLE;
3004
}
3005
return false; // unreachable
3006
}
3007
3008
bool Value::operator<=(const Value& other) const { return !(other < *this); }
3009
3010
bool Value::operator>=(const Value& other) const { return !(*this < other); }
3011
3012
bool Value::operator>(const Value& other) const { return other < *this; }
3013
3014
bool Value::operator==(const Value& other) const {
3015
if (type() != other.type())
3016
return false;
3017
switch (type()) {
3018
case nullValue:
3019
return true;
3020
case intValue:
3021
return value_.int_ == other.value_.int_;
3022
case uintValue:
3023
return value_.uint_ == other.value_.uint_;
3024
case realValue:
3025
return value_.real_ == other.value_.real_;
3026
case booleanValue:
3027
return value_.bool_ == other.value_.bool_;
3028
case stringValue: {
3029
if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
3030
return (value_.string_ == other.value_.string_);
3031
}
3032
unsigned this_len;
3033
unsigned other_len;
3034
char const* this_str;
3035
char const* other_str;
3036
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
3037
&this_str);
3038
decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
3039
&other_str);
3040
if (this_len != other_len)
3041
return false;
3042
JSON_ASSERT(this_str && other_str);
3043
int comp = memcmp(this_str, other_str, this_len);
3044
return comp == 0;
3045
}
3046
case arrayValue:
3047
case objectValue:
3048
return value_.map_->size() == other.value_.map_->size() &&
3049
(*value_.map_) == (*other.value_.map_);
3050
default:
3051
JSON_ASSERT_UNREACHABLE;
3052
}
3053
return false; // unreachable
3054
}
3055
3056
bool Value::operator!=(const Value& other) const { return !(*this == other); }
3057
3058
const char* Value::asCString() const {
3059
JSON_ASSERT_MESSAGE(type() == stringValue,
3060
"in Json::Value::asCString(): requires stringValue");
3061
if (value_.string_ == nullptr)
3062
return nullptr;
3063
unsigned this_len;
3064
char const* this_str;
3065
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
3066
&this_str);
3067
return this_str;
3068
}
3069
3070
#if JSONCPP_USING_SECURE_MEMORY
3071
unsigned Value::getCStringLength() const {
3072
JSON_ASSERT_MESSAGE(type() == stringValue,
3073
"in Json::Value::asCString(): requires stringValue");
3074
if (value_.string_ == 0)
3075
return 0;
3076
unsigned this_len;
3077
char const* this_str;
3078
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
3079
&this_str);
3080
return this_len;
3081
}
3082
#endif
3083
3084
bool Value::getString(char const** begin, char const** end) const {
3085
if (type() != stringValue)
3086
return false;
3087
if (value_.string_ == nullptr)
3088
return false;
3089
unsigned length;
3090
decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
3091
begin);
3092
*end = *begin + length;
3093
return true;
3094
}
3095
3096
String Value::asString() const {
3097
switch (type()) {
3098
case nullValue:
3099
return "";
3100
case stringValue: {
3101
if (value_.string_ == nullptr)
3102
return "";
3103
unsigned this_len;
3104
char const* this_str;
3105
decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
3106
&this_str);
3107
return String(this_str, this_len);
3108
}
3109
case booleanValue:
3110
return value_.bool_ ? "true" : "false";
3111
case intValue:
3112
return valueToString(value_.int_);
3113
case uintValue:
3114
return valueToString(value_.uint_);
3115
case realValue:
3116
return valueToString(value_.real_);
3117
default:
3118
JSON_FAIL_MESSAGE("Type is not convertible to string");
3119
}
3120
}
3121
3122
#ifdef JSON_USE_CPPTL
3123
CppTL::ConstString Value::asConstString() const {
3124
unsigned len;
3125
char const* str;
3126
decodePrefixedString(isAllocated(), value_.string_, &len, &str);
3127
return CppTL::ConstString(str, len);
3128
}
3129
#endif
3130
3131
Value::Int Value::asInt() const {
3132
switch (type()) {
3133
case intValue:
3134
JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
3135
return Int(value_.int_);
3136
case uintValue:
3137
JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
3138
return Int(value_.uint_);
3139
case realValue:
3140
JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
3141
"double out of Int range");
3142
return Int(value_.real_);
3143
case nullValue:
3144
return 0;
3145
case booleanValue:
3146
return value_.bool_ ? 1 : 0;
3147
default:
3148
break;
3149
}
3150
JSON_FAIL_MESSAGE("Value is not convertible to Int.");
3151
}
3152
3153
Value::UInt Value::asUInt() const {
3154
switch (type()) {
3155
case intValue:
3156
JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
3157
return UInt(value_.int_);
3158
case uintValue:
3159
JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
3160
return UInt(value_.uint_);
3161
case realValue:
3162
JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
3163
"double out of UInt range");
3164
return UInt(value_.real_);
3165
case nullValue:
3166
return 0;
3167
case booleanValue:
3168
return value_.bool_ ? 1 : 0;
3169
default:
3170
break;
3171
}
3172
JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
3173
}
3174
3175
#if defined(JSON_HAS_INT64)
3176
3177
Value::Int64 Value::asInt64() const {
3178
switch (type()) {
3179
case intValue:
3180
return Int64(value_.int_);
3181
case uintValue:
3182
JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
3183
return Int64(value_.uint_);
3184
case realValue:
3185
JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
3186
"double out of Int64 range");
3187
return Int64(value_.real_);
3188
case nullValue:
3189
return 0;
3190
case booleanValue:
3191
return value_.bool_ ? 1 : 0;
3192
default:
3193
break;
3194
}
3195
JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
3196
}
3197
3198
Value::UInt64 Value::asUInt64() const {
3199
switch (type()) {
3200
case intValue:
3201
JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
3202
return UInt64(value_.int_);
3203
case uintValue:
3204
return UInt64(value_.uint_);
3205
case realValue:
3206
JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
3207
"double out of UInt64 range");
3208
return UInt64(value_.real_);
3209
case nullValue:
3210
return 0;
3211
case booleanValue:
3212
return value_.bool_ ? 1 : 0;
3213
default:
3214
break;
3215
}
3216
JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
3217
}
3218
#endif // if defined(JSON_HAS_INT64)
3219
3220
LargestInt Value::asLargestInt() const {
3221
#if defined(JSON_NO_INT64)
3222
return asInt();
3223
#else
3224
return asInt64();
3225
#endif
3226
}
3227
3228
LargestUInt Value::asLargestUInt() const {
3229
#if defined(JSON_NO_INT64)
3230
return asUInt();
3231
#else
3232
return asUInt64();
3233
#endif
3234
}
3235
3236
double Value::asDouble() const {
3237
switch (type()) {
3238
case intValue:
3239
return static_cast<double>(value_.int_);
3240
case uintValue:
3241
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3242
return static_cast<double>(value_.uint_);
3243
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3244
return integerToDouble(value_.uint_);
3245
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3246
case realValue:
3247
return value_.real_;
3248
case nullValue:
3249
return 0.0;
3250
case booleanValue:
3251
return value_.bool_ ? 1.0 : 0.0;
3252
default:
3253
break;
3254
}
3255
JSON_FAIL_MESSAGE("Value is not convertible to double.");
3256
}
3257
3258
float Value::asFloat() const {
3259
switch (type()) {
3260
case intValue:
3261
return static_cast<float>(value_.int_);
3262
case uintValue:
3263
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3264
return static_cast<float>(value_.uint_);
3265
#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3266
// This can fail (silently?) if the value is bigger than MAX_FLOAT.
3267
return static_cast<float>(integerToDouble(value_.uint_));
3268
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
3269
case realValue:
3270
return static_cast<float>(value_.real_);
3271
case nullValue:
3272
return 0.0;
3273
case booleanValue:
3274
return value_.bool_ ? 1.0f : 0.0f;
3275
default:
3276
break;
3277
}
3278
JSON_FAIL_MESSAGE("Value is not convertible to float.");
3279
}
3280
3281
bool Value::asBool() const {
3282
switch (type()) {
3283
case booleanValue:
3284
return value_.bool_;
3285
case nullValue:
3286
return false;
3287
case intValue:
3288
return value_.int_ ? true : false;
3289
case uintValue:
3290
return value_.uint_ ? true : false;
3291
case realValue: {
3292
// According to JavaScript language zero or NaN is regarded as false
3293
const auto value_classification = std::fpclassify(value_.real_);
3294
return value_classification != FP_ZERO && value_classification != FP_NAN;
3295
}
3296
default:
3297
break;
3298
}
3299
JSON_FAIL_MESSAGE("Value is not convertible to bool.");
3300
}
3301
3302
bool Value::isConvertibleTo(ValueType other) const {
3303
switch (other) {
3304
case nullValue:
3305
return (isNumeric() && asDouble() == 0.0) ||
3306
(type() == booleanValue && value_.bool_ == false) ||
3307
(type() == stringValue && asString().empty()) ||
3308
(type() == arrayValue && value_.map_->empty()) ||
3309
(type() == objectValue && value_.map_->empty()) ||
3310
type() == nullValue;
3311
case intValue:
3312
return isInt() ||
3313
(type() == realValue && InRange(value_.real_, minInt, maxInt)) ||
3314
type() == booleanValue || type() == nullValue;
3315
case uintValue:
3316
return isUInt() ||
3317
(type() == realValue && InRange(value_.real_, 0, maxUInt)) ||
3318
type() == booleanValue || type() == nullValue;
3319
case realValue:
3320
return isNumeric() || type() == booleanValue || type() == nullValue;
3321
case booleanValue:
3322
return isNumeric() || type() == booleanValue || type() == nullValue;
3323
case stringValue:
3324
return isNumeric() || type() == booleanValue || type() == stringValue ||
3325
type() == nullValue;
3326
case arrayValue:
3327
return type() == arrayValue || type() == nullValue;
3328
case objectValue:
3329
return type() == objectValue || type() == nullValue;
3330
}
3331
JSON_ASSERT_UNREACHABLE;
3332
return false;
3333
}
3334
3335
/// Number of values in array or object
3336
ArrayIndex Value::size() const {
3337
switch (type()) {
3338
case nullValue:
3339
case intValue:
3340
case uintValue:
3341
case realValue:
3342
case booleanValue:
3343
case stringValue:
3344
return 0;
3345
case arrayValue: // size of the array is highest index + 1
3346
if (!value_.map_->empty()) {
3347
ObjectValues::const_iterator itLast = value_.map_->end();
3348
--itLast;
3349
return (*itLast).first.index() + 1;
3350
}
3351
return 0;
3352
case objectValue:
3353
return ArrayIndex(value_.map_->size());
3354
}
3355
JSON_ASSERT_UNREACHABLE;
3356
return 0; // unreachable;
3357
}
3358
3359
bool Value::empty() const {
3360
if (isNull() || isArray() || isObject())
3361
return size() == 0u;
3362
else
3363
return false;
3364
}
3365
3366
Value::operator bool() const { return !isNull(); }
3367
3368
void Value::clear() {
3369
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
3370
type() == objectValue,
3371
"in Json::Value::clear(): requires complex value");
3372
start_ = 0;
3373
limit_ = 0;
3374
switch (type()) {
3375
case arrayValue:
3376
case objectValue:
3377
value_.map_->clear();
3378
break;
3379
default:
3380
break;
3381
}
3382
}
3383
3384
void Value::resize(ArrayIndex newSize) {
3385
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
3386
"in Json::Value::resize(): requires arrayValue");
3387
if (type() == nullValue)
3388
*this = Value(arrayValue);
3389
ArrayIndex oldSize = size();
3390
if (newSize == 0)
3391
clear();
3392
else if (newSize > oldSize)
3393
this->operator[](newSize - 1);
3394
else {
3395
for (ArrayIndex index = newSize; index < oldSize; ++index) {
3396
value_.map_->erase(index);
3397
}
3398
JSON_ASSERT(size() == newSize);
3399
}
3400
}
3401
3402
Value& Value::operator[](ArrayIndex index) {
3403
JSON_ASSERT_MESSAGE(
3404
type() == nullValue || type() == arrayValue,
3405
"in Json::Value::operator[](ArrayIndex): requires arrayValue");
3406
if (type() == nullValue)
3407
*this = Value(arrayValue);
3408
CZString key(index);
3409
auto it = value_.map_->lower_bound(key);
3410
if (it != value_.map_->end() && (*it).first == key)
3411
return (*it).second;
3412
3413
ObjectValues::value_type defaultValue(key, nullSingleton());
3414
it = value_.map_->insert(it, defaultValue);
3415
return (*it).second;
3416
}
3417
3418
Value& Value::operator[](int index) {
3419
JSON_ASSERT_MESSAGE(
3420
index >= 0,
3421
"in Json::Value::operator[](int index): index cannot be negative");
3422
return (*this)[ArrayIndex(index)];
3423
}
3424
3425
const Value& Value::operator[](ArrayIndex index) const {
3426
JSON_ASSERT_MESSAGE(
3427
type() == nullValue || type() == arrayValue,
3428
"in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
3429
if (type() == nullValue)
3430
return nullSingleton();
3431
CZString key(index);
3432
ObjectValues::const_iterator it = value_.map_->find(key);
3433
if (it == value_.map_->end())
3434
return nullSingleton();
3435
return (*it).second;
3436
}
3437
3438
const Value& Value::operator[](int index) const {
3439
JSON_ASSERT_MESSAGE(
3440
index >= 0,
3441
"in Json::Value::operator[](int index) const: index cannot be negative");
3442
return (*this)[ArrayIndex(index)];
3443
}
3444
3445
void Value::initBasic(ValueType type, bool allocated) {
3446
setType(type);
3447
setIsAllocated(allocated);
3448
comments_ = Comments{};
3449
start_ = 0;
3450
limit_ = 0;
3451
}
3452
3453
void Value::dupPayload(const Value& other) {
3454
setType(other.type());
3455
setIsAllocated(false);
3456
switch (type()) {
3457
case nullValue:
3458
case intValue:
3459
case uintValue:
3460
case realValue:
3461
case booleanValue:
3462
value_ = other.value_;
3463
break;
3464
case stringValue:
3465
if (other.value_.string_ && other.isAllocated()) {
3466
unsigned len;
3467
char const* str;
3468
decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
3469
&str);
3470
value_.string_ = duplicateAndPrefixStringValue(str, len);
3471
setIsAllocated(true);
3472
} else {
3473
value_.string_ = other.value_.string_;
3474
}
3475
break;
3476
case arrayValue:
3477
case objectValue:
3478
value_.map_ = new ObjectValues(*other.value_.map_);
3479
break;
3480
default:
3481
JSON_ASSERT_UNREACHABLE;
3482
}
3483
}
3484
3485
void Value::releasePayload() {
3486
switch (type()) {
3487
case nullValue:
3488
case intValue:
3489
case uintValue:
3490
case realValue:
3491
case booleanValue:
3492
break;
3493
case stringValue:
3494
if (isAllocated())
3495
releasePrefixedStringValue(value_.string_);
3496
break;
3497
case arrayValue:
3498
case objectValue:
3499
delete value_.map_;
3500
break;
3501
default:
3502
JSON_ASSERT_UNREACHABLE;
3503
}
3504
}
3505
3506
void Value::dupMeta(const Value& other) {
3507
comments_ = other.comments_;
3508
start_ = other.start_;
3509
limit_ = other.limit_;
3510
}
3511
3512
// Access an object value by name, create a null member if it does not exist.
3513
// @pre Type of '*this' is object or null.
3514
// @param key is null-terminated.
3515
Value& Value::resolveReference(const char* key) {
3516
JSON_ASSERT_MESSAGE(
3517
type() == nullValue || type() == objectValue,
3518
"in Json::Value::resolveReference(): requires objectValue");
3519
if (type() == nullValue)
3520
*this = Value(objectValue);
3521
CZString actualKey(key, static_cast<unsigned>(strlen(key)),
3522
CZString::noDuplication); // NOTE!
3523
auto it = value_.map_->lower_bound(actualKey);
3524
if (it != value_.map_->end() && (*it).first == actualKey)
3525
return (*it).second;
3526
3527
ObjectValues::value_type defaultValue(actualKey, nullSingleton());
3528
it = value_.map_->insert(it, defaultValue);
3529
Value& value = (*it).second;
3530
return value;
3531
}
3532
3533
// @param key is not null-terminated.
3534
Value& Value::resolveReference(char const* key, char const* end) {
3535
JSON_ASSERT_MESSAGE(
3536
type() == nullValue || type() == objectValue,
3537
"in Json::Value::resolveReference(key, end): requires objectValue");
3538
if (type() == nullValue)
3539
*this = Value(objectValue);
3540
CZString actualKey(key, static_cast<unsigned>(end - key),
3541
CZString::duplicateOnCopy);
3542
auto it = value_.map_->lower_bound(actualKey);
3543
if (it != value_.map_->end() && (*it).first == actualKey)
3544
return (*it).second;
3545
3546
ObjectValues::value_type defaultValue(actualKey, nullSingleton());
3547
it = value_.map_->insert(it, defaultValue);
3548
Value& value = (*it).second;
3549
return value;
3550
}
3551
3552
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
3553
const Value* value = &((*this)[index]);
3554
return value == &nullSingleton() ? defaultValue : *value;
3555
}
3556
3557
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
3558
3559
Value const* Value::find(char const* begin, char const* end) const {
3560
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
3561
"in Json::Value::find(begin, end): requires "
3562
"objectValue or nullValue");
3563
if (type() == nullValue)
3564
return nullptr;
3565
CZString actualKey(begin, static_cast<unsigned>(end - begin),
3566
CZString::noDuplication);
3567
ObjectValues::const_iterator it = value_.map_->find(actualKey);
3568
if (it == value_.map_->end())
3569
return nullptr;
3570
return &(*it).second;
3571
}
3572
Value* Value::demand(char const* begin, char const* end) {
3573
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
3574
"in Json::Value::demand(begin, end): requires "
3575
"objectValue or nullValue");
3576
return &resolveReference(begin, end);
3577
}
3578
const Value& Value::operator[](const char* key) const {
3579
Value const* found = find(key, key + strlen(key));
3580
if (!found)
3581
return nullSingleton();
3582
return *found;
3583
}
3584
Value const& Value::operator[](const String& key) const {
3585
Value const* found = find(key.data(), key.data() + key.length());
3586
if (!found)
3587
return nullSingleton();
3588
return *found;
3589
}
3590
3591
Value& Value::operator[](const char* key) {
3592
return resolveReference(key, key + strlen(key));
3593
}
3594
3595
Value& Value::operator[](const String& key) {
3596
return resolveReference(key.data(), key.data() + key.length());
3597
}
3598
3599
Value& Value::operator[](const StaticString& key) {
3600
return resolveReference(key.c_str());
3601
}
3602
3603
#ifdef JSON_USE_CPPTL
3604
Value& Value::operator[](const CppTL::ConstString& key) {
3605
return resolveReference(key.c_str(), key.end_c_str());
3606
}
3607
Value const& Value::operator[](CppTL::ConstString const& key) const {
3608
Value const* found = find(key.c_str(), key.end_c_str());
3609
if (!found)
3610
return nullSingleton();
3611
return *found;
3612
}
3613
#endif
3614
3615
Value& Value::append(const Value& value) { return (*this)[size()] = value; }
3616
3617
Value& Value::append(Value&& value) {
3618
return (*this)[size()] = std::move(value);
3619
}
3620
3621
Value Value::get(char const* begin,
3622
char const* end,
3623
Value const& defaultValue) const {
3624
Value const* found = find(begin, end);
3625
return !found ? defaultValue : *found;
3626
}
3627
Value Value::get(char const* key, Value const& defaultValue) const {
3628
return get(key, key + strlen(key), defaultValue);
3629
}
3630
Value Value::get(String const& key, Value const& defaultValue) const {
3631
return get(key.data(), key.data() + key.length(), defaultValue);
3632
}
3633
3634
bool Value::removeMember(const char* begin, const char* end, Value* removed) {
3635
if (type() != objectValue) {
3636
return false;
3637
}
3638
CZString actualKey(begin, static_cast<unsigned>(end - begin),
3639
CZString::noDuplication);
3640
auto it = value_.map_->find(actualKey);
3641
if (it == value_.map_->end())
3642
return false;
3643
if (removed)
3644
*removed = std::move(it->second);
3645
value_.map_->erase(it);
3646
return true;
3647
}
3648
bool Value::removeMember(const char* key, Value* removed) {
3649
return removeMember(key, key + strlen(key), removed);
3650
}
3651
bool Value::removeMember(String const& key, Value* removed) {
3652
return removeMember(key.data(), key.data() + key.length(), removed);
3653
}
3654
void Value::removeMember(const char* key) {
3655
JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
3656
"in Json::Value::removeMember(): requires objectValue");
3657
if (type() == nullValue)
3658
return;
3659
3660
CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
3661
value_.map_->erase(actualKey);
3662
}
3663
void Value::removeMember(const String& key) { removeMember(key.c_str()); }
3664
3665
bool Value::removeIndex(ArrayIndex index, Value* removed) {
3666
if (type() != arrayValue) {
3667
return false;
3668
}
3669
CZString key(index);
3670
auto it = value_.map_->find(key);
3671
if (it == value_.map_->end()) {
3672
return false;
3673
}
3674
if (removed)
3675
*removed = it->second;
3676
ArrayIndex oldSize = size();
3677
// shift left all items left, into the place of the "removed"
3678
for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
3679
CZString keey(i);
3680
(*value_.map_)[keey] = (*this)[i + 1];
3681
}
3682
// erase the last one ("leftover")
3683
CZString keyLast(oldSize - 1);
3684
auto itLast = value_.map_->find(keyLast);
3685
value_.map_->erase(itLast);
3686
return true;
3687
}
3688
3689
#ifdef JSON_USE_CPPTL
3690
Value Value::get(const CppTL::ConstString& key,
3691
const Value& defaultValue) const {
3692
return get(key.c_str(), key.end_c_str(), defaultValue);
3693
}
3694
#endif
3695
3696
bool Value::isMember(char const* begin, char const* end) const {
3697
Value const* value = find(begin, end);
3698
return nullptr != value;
3699
}
3700
bool Value::isMember(char const* key) const {
3701
return isMember(key, key + strlen(key));
3702
}
3703
bool Value::isMember(String const& key) const {
3704
return isMember(key.data(), key.data() + key.length());
3705
}
3706
3707
#ifdef JSON_USE_CPPTL
3708
bool Value::isMember(const CppTL::ConstString& key) const {
3709
return isMember(key.c_str(), key.end_c_str());
3710
}
3711
#endif
3712
3713
Value::Members Value::getMemberNames() const {
3714
JSON_ASSERT_MESSAGE(
3715
type() == nullValue || type() == objectValue,
3716
"in Json::Value::getMemberNames(), value must be objectValue");
3717
if (type() == nullValue)
3718
return Value::Members();
3719
Members members;
3720
members.reserve(value_.map_->size());
3721
ObjectValues::const_iterator it = value_.map_->begin();
3722
ObjectValues::const_iterator itEnd = value_.map_->end();
3723
for (; it != itEnd; ++it) {
3724
members.push_back(String((*it).first.data(), (*it).first.length()));
3725
}
3726
return members;
3727
}
3728
//
3729
//# ifdef JSON_USE_CPPTL
3730
// EnumMemberNames
3731
// Value::enumMemberNames() const
3732
//{
3733
// if ( type() == objectValue )
3734
// {
3735
// return CppTL::Enum::any( CppTL::Enum::transform(
3736
// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
3737
// MemberNamesTransform() ) );
3738
// }
3739
// return EnumMemberNames();
3740
//}
3741
//
3742
//
3743
// EnumValues
3744
// Value::enumValues() const
3745
//{
3746
// if ( type() == objectValue || type() == arrayValue )
3747
// return CppTL::Enum::anyValues( *(value_.map_),
3748
// CppTL::Type<const Value &>() );
3749
// return EnumValues();
3750
//}
3751
//
3752
//# endif
3753
3754
static bool IsIntegral(double d) {
3755
double integral_part;
3756
return modf(d, &integral_part) == 0.0;
3757
}
3758
3759
bool Value::isNull() const { return type() == nullValue; }
3760
3761
bool Value::isBool() const { return type() == booleanValue; }
3762
3763
bool Value::isInt() const {
3764
switch (type()) {
3765
case intValue:
3766
#if defined(JSON_HAS_INT64)
3767
return value_.int_ >= minInt && value_.int_ <= maxInt;
3768
#else
3769
return true;
3770
#endif
3771
case uintValue:
3772
return value_.uint_ <= UInt(maxInt);
3773
case realValue:
3774
return value_.real_ >= minInt && value_.real_ <= maxInt &&
3775
IsIntegral(value_.real_);
3776
default:
3777
break;
3778
}
3779
return false;
3780
}
3781
3782
bool Value::isUInt() const {
3783
switch (type()) {
3784
case intValue:
3785
#if defined(JSON_HAS_INT64)
3786
return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
3787
#else
3788
return value_.int_ >= 0;
3789
#endif
3790
case uintValue:
3791
#if defined(JSON_HAS_INT64)
3792
return value_.uint_ <= maxUInt;
3793
#else
3794
return true;
3795
#endif
3796
case realValue:
3797
return value_.real_ >= 0 && value_.real_ <= maxUInt &&
3798
IsIntegral(value_.real_);
3799
default:
3800
break;
3801
}
3802
return false;
3803
}
3804
3805
bool Value::isInt64() const {
3806
#if defined(JSON_HAS_INT64)
3807
switch (type()) {
3808
case intValue:
3809
return true;
3810
case uintValue:
3811
return value_.uint_ <= UInt64(maxInt64);
3812
case realValue:
3813
// Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
3814
// double, so double(maxInt64) will be rounded up to 2^63. Therefore we
3815
// require the value to be strictly less than the limit.
3816
return value_.real_ >= double(minInt64) &&
3817
value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
3818
default:
3819
break;
3820
}
3821
#endif // JSON_HAS_INT64
3822
return false;
3823
}
3824
3825
bool Value::isUInt64() const {
3826
#if defined(JSON_HAS_INT64)
3827
switch (type()) {
3828
case intValue:
3829
return value_.int_ >= 0;
3830
case uintValue:
3831
return true;
3832
case realValue:
3833
// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3834
// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3835
// require the value to be strictly less than the limit.
3836
return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
3837
IsIntegral(value_.real_);
3838
default:
3839
break;
3840
}
3841
#endif // JSON_HAS_INT64
3842
return false;
3843
}
3844
3845
bool Value::isIntegral() const {
3846
switch (type()) {
3847
case intValue:
3848
case uintValue:
3849
return true;
3850
case realValue:
3851
#if defined(JSON_HAS_INT64)
3852
// Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
3853
// double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
3854
// require the value to be strictly less than the limit.
3855
return value_.real_ >= double(minInt64) &&
3856
value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
3857
#else
3858
return value_.real_ >= minInt && value_.real_ <= maxUInt &&
3859
IsIntegral(value_.real_);
3860
#endif // JSON_HAS_INT64
3861
default:
3862
break;
3863
}
3864
return false;
3865
}
3866
3867
bool Value::isDouble() const {
3868
return type() == intValue || type() == uintValue || type() == realValue;
3869
}
3870
3871
bool Value::isNumeric() const { return isDouble(); }
3872
3873
bool Value::isString() const { return type() == stringValue; }
3874
3875
bool Value::isArray() const { return type() == arrayValue; }
3876
3877
bool Value::isObject() const { return type() == objectValue; }
3878
3879
Value::Comments::Comments(const Comments& that)
3880
: ptr_{cloneUnique(that.ptr_)} {}
3881
3882
Value::Comments::Comments(Comments&& that) : ptr_{std::move(that.ptr_)} {}
3883
3884
Value::Comments& Value::Comments::operator=(const Comments& that) {
3885
ptr_ = cloneUnique(that.ptr_);
3886
return *this;
3887
}
3888
3889
Value::Comments& Value::Comments::operator=(Comments&& that) {
3890
ptr_ = std::move(that.ptr_);
3891
return *this;
3892
}
3893
3894
bool Value::Comments::has(CommentPlacement slot) const {
3895
return ptr_ && !(*ptr_)[slot].empty();
3896
}
3897
3898
String Value::Comments::get(CommentPlacement slot) const {
3899
if (!ptr_)
3900
return {};
3901
return (*ptr_)[slot];
3902
}
3903
3904
void Value::Comments::set(CommentPlacement slot, String comment) {
3905
if (!ptr_) {
3906
ptr_ = std::unique_ptr<Array>(new Array());
3907
}
3908
(*ptr_)[slot] = std::move(comment);
3909
}
3910
3911
void Value::setComment(String comment, CommentPlacement placement) {
3912
if (!comment.empty() && (comment.back() == '\n')) {
3913
// Always discard trailing newline, to aid indentation.
3914
comment.pop_back();
3915
}
3916
JSON_ASSERT(!comment.empty());
3917
JSON_ASSERT_MESSAGE(
3918
comment[0] == '\0' || comment[0] == '/',
3919
"in Json::Value::setComment(): Comments must start with /");
3920
comments_.set(placement, std::move(comment));
3921
}
3922
3923
bool Value::hasComment(CommentPlacement placement) const {
3924
return comments_.has(placement);
3925
}
3926
3927
String Value::getComment(CommentPlacement placement) const {
3928
return comments_.get(placement);
3929
}
3930
3931
void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
3932
3933
void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
3934
3935
ptrdiff_t Value::getOffsetStart() const { return start_; }
3936
3937
ptrdiff_t Value::getOffsetLimit() const { return limit_; }
3938
3939
String Value::toStyledString() const {
3940
StreamWriterBuilder builder;
3941
3942
String out = this->hasComment(commentBefore) ? "\n" : "";
3943
out += Json::writeString(builder, *this);
3944
out += '\n';
3945
3946
return out;
3947
}
3948
3949
Value::const_iterator Value::begin() const {
3950
switch (type()) {
3951
case arrayValue:
3952
case objectValue:
3953
if (value_.map_)
3954
return const_iterator(value_.map_->begin());
3955
break;
3956
default:
3957
break;
3958
}
3959
return {};
3960
}
3961
3962
Value::const_iterator Value::end() const {
3963
switch (type()) {
3964
case arrayValue:
3965
case objectValue:
3966
if (value_.map_)
3967
return const_iterator(value_.map_->end());
3968
break;
3969
default:
3970
break;
3971
}
3972
return {};
3973
}
3974
3975
Value::iterator Value::begin() {
3976
switch (type()) {
3977
case arrayValue:
3978
case objectValue:
3979
if (value_.map_)
3980
return iterator(value_.map_->begin());
3981
break;
3982
default:
3983
break;
3984
}
3985
return iterator();
3986
}
3987
3988
Value::iterator Value::end() {
3989
switch (type()) {
3990
case arrayValue:
3991
case objectValue:
3992
if (value_.map_)
3993
return iterator(value_.map_->end());
3994
break;
3995
default:
3996
break;
3997
}
3998
return iterator();
3999
}
4000
4001
// class PathArgument
4002
// //////////////////////////////////////////////////////////////////
4003
4004
PathArgument::PathArgument() : key_() {}
4005
4006
PathArgument::PathArgument(ArrayIndex index)
4007
: key_(), index_(index), kind_(kindIndex) {}
4008
4009
PathArgument::PathArgument(const char* key)
4010
: key_(key), index_(), kind_(kindKey) {}
4011
4012
PathArgument::PathArgument(const String& key)
4013
: key_(key.c_str()), index_(), kind_(kindKey) {}
4014
4015
// class Path
4016
// //////////////////////////////////////////////////////////////////
4017
4018
Path::Path(const String& path,
4019
const PathArgument& a1,
4020
const PathArgument& a2,
4021
const PathArgument& a3,
4022
const PathArgument& a4,
4023
const PathArgument& a5) {
4024
InArgs in;
4025
in.reserve(5);
4026
in.push_back(&a1);
4027
in.push_back(&a2);
4028
in.push_back(&a3);
4029
in.push_back(&a4);
4030
in.push_back(&a5);
4031
makePath(path, in);
4032
}
4033
4034
void Path::makePath(const String& path, const InArgs& in) {
4035
const char* current = path.c_str();
4036
const char* end = current + path.length();
4037
auto itInArg = in.begin();
4038
while (current != end) {
4039
if (*current == '[') {
4040
++current;
4041
if (*current == '%')
4042
addPathInArg(path, in, itInArg, PathArgument::kindIndex);
4043
else {
4044
ArrayIndex index = 0;
4045
for (; current != end && *current >= '0' && *current <= '9'; ++current)
4046
index = index * 10 + ArrayIndex(*current - '0');
4047
args_.push_back(index);
4048
}
4049
if (current == end || *++current != ']')
4050
invalidPath(path, int(current - path.c_str()));
4051
} else if (*current == '%') {
4052
addPathInArg(path, in, itInArg, PathArgument::kindKey);
4053
++current;
4054
} else if (*current == '.' || *current == ']') {
4055
++current;
4056
} else {
4057
const char* beginName = current;
4058
while (current != end && !strchr("[.", *current))
4059
++current;
4060
args_.push_back(String(beginName, current));
4061
}
4062
}
4063
}
4064
4065
void Path::addPathInArg(const String& /*path*/,
4066
const InArgs& in,
4067
InArgs::const_iterator& itInArg,
4068
PathArgument::Kind kind) {
4069
if (itInArg == in.end()) {
4070
// Error: missing argument %d
4071
} else if ((*itInArg)->kind_ != kind) {
4072
// Error: bad argument type
4073
} else {
4074
args_.push_back(**itInArg++);
4075
}
4076
}
4077
4078
void Path::invalidPath(const String& /*path*/, int /*location*/) {
4079
// Error: invalid path.
4080
}
4081
4082
const Value& Path::resolve(const Value& root) const {
4083
const Value* node = &root;
4084
for (const auto& arg : args_) {
4085
if (arg.kind_ == PathArgument::kindIndex) {
4086
if (!node->isArray() || !node->isValidIndex(arg.index_)) {
4087
// Error: unable to resolve path (array value expected at position... )
4088
return Value::nullSingleton();
4089
}
4090
node = &((*node)[arg.index_]);
4091
} else if (arg.kind_ == PathArgument::kindKey) {
4092
if (!node->isObject()) {
4093
// Error: unable to resolve path (object value expected at position...)
4094
return Value::nullSingleton();
4095
}
4096
node = &((*node)[arg.key_]);
4097
if (node == &Value::nullSingleton()) {
4098
// Error: unable to resolve path (object has no member named '' at
4099
// position...)
4100
return Value::nullSingleton();
4101
}
4102
}
4103
}
4104
return *node;
4105
}
4106
4107
Value Path::resolve(const Value& root, const Value& defaultValue) const {
4108
const Value* node = &root;
4109
for (const auto& arg : args_) {
4110
if (arg.kind_ == PathArgument::kindIndex) {
4111
if (!node->isArray() || !node->isValidIndex(arg.index_))
4112
return defaultValue;
4113
node = &((*node)[arg.index_]);
4114
} else if (arg.kind_ == PathArgument::kindKey) {
4115
if (!node->isObject())
4116
return defaultValue;
4117
node = &((*node)[arg.key_]);
4118
if (node == &Value::nullSingleton())
4119
return defaultValue;
4120
}
4121
}
4122
return *node;
4123
}
4124
4125
Value& Path::make(Value& root) const {
4126
Value* node = &root;
4127
for (const auto& arg : args_) {
4128
if (arg.kind_ == PathArgument::kindIndex) {
4129
if (!node->isArray()) {
4130
// Error: node is not an array at position ...
4131
}
4132
node = &((*node)[arg.index_]);
4133
} else if (arg.kind_ == PathArgument::kindKey) {
4134
if (!node->isObject()) {
4135
// Error: node is not an object at position...
4136
}
4137
node = &((*node)[arg.key_]);
4138
}
4139
}
4140
return *node;
4141
}
4142
4143
} // namespace Json
4144
4145
// //////////////////////////////////////////////////////////////////////
4146
// End of content of file: src/lib_json/json_value.cpp
4147
// //////////////////////////////////////////////////////////////////////
4148
4149
4150
4151
4152
4153
4154
// //////////////////////////////////////////////////////////////////////
4155
// Beginning of content of file: src/lib_json/json_writer.cpp
4156
// //////////////////////////////////////////////////////////////////////
4157
4158
// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
4159
// Distributed under MIT license, or public domain if desired and
4160
// recognized in your jurisdiction.
4161
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
4162
4163
#if !defined(JSON_IS_AMALGAMATION)
4164
#include "json_tool.h"
4165
#include <json/writer.h>
4166
#endif // if !defined(JSON_IS_AMALGAMATION)
4167
#include <cassert>
4168
#include <cstring>
4169
#include <iomanip>
4170
#include <memory>
4171
#include <set>
4172
#include <sstream>
4173
#include <utility>
4174
4175
#if __cplusplus >= 201103L
4176
#include <cmath>
4177
#include <cstdio>
4178
4179
#if !defined(isnan)
4180
#define isnan std::isnan
4181
#endif
4182
4183
#if !defined(isfinite)
4184
#define isfinite std::isfinite
4185
#endif
4186
4187
#else
4188
#include <cmath>
4189
#include <cstdio>
4190
4191
#if defined(_MSC_VER)
4192
#if !defined(isnan)
4193
#include <float.h>
4194
#define isnan _isnan
4195
#endif
4196
4197
#if !defined(isfinite)
4198
#include <float.h>
4199
#define isfinite _finite
4200
#endif
4201
4202
#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
4203
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
4204
#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
4205
4206
#endif //_MSC_VER
4207
4208
#if defined(__sun) && defined(__SVR4) // Solaris
4209
#if !defined(isfinite)
4210
#include <ieeefp.h>
4211
#define isfinite finite
4212
#endif
4213
#endif
4214
4215
#if defined(__hpux)
4216
#if !defined(isfinite)
4217
#if defined(__ia64) && !defined(finite)
4218
#define isfinite(x) \
4219
((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x)))
4220
#endif
4221
#endif
4222
#endif
4223
4224
#if !defined(isnan)
4225
// IEEE standard states that NaN values will not compare to themselves
4226
#define isnan(x) (x != x)
4227
#endif
4228
4229
#if !defined(__APPLE__)
4230
#if !defined(isfinite)
4231
#define isfinite finite
4232
#endif
4233
#endif
4234
#endif
4235
4236
#if defined(_MSC_VER)
4237
// Disable warning about strdup being deprecated.
4238
#pragma warning(disable : 4996)
4239
#endif
4240
4241
namespace Json {
4242
4243
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
4244
typedef std::unique_ptr<StreamWriter> StreamWriterPtr;
4245
#else
4246
typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
4247
#endif
4248
4249
String valueToString(LargestInt value) {
4250
UIntToStringBuffer buffer;
4251
char* current = buffer + sizeof(buffer);
4252
if (value == Value::minLargestInt) {
4253
uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
4254
*--current = '-';
4255
} else if (value < 0) {
4256
uintToString(LargestUInt(-value), current);
4257
*--current = '-';
4258
} else {
4259
uintToString(LargestUInt(value), current);
4260
}
4261
assert(current >= buffer);
4262
return current;
4263
}
4264
4265
String valueToString(LargestUInt value) {
4266
UIntToStringBuffer buffer;
4267
char* current = buffer + sizeof(buffer);
4268
uintToString(value, current);
4269
assert(current >= buffer);
4270
return current;
4271
}
4272
4273
#if defined(JSON_HAS_INT64)
4274
4275
String valueToString(Int value) { return valueToString(LargestInt(value)); }
4276
4277
String valueToString(UInt value) { return valueToString(LargestUInt(value)); }
4278
4279
#endif // # if defined(JSON_HAS_INT64)
4280
4281
namespace {
4282
String valueToString(double value,
4283
bool useSpecialFloats,
4284
unsigned int precision,
4285
PrecisionType precisionType) {
4286
// Print into the buffer. We need not request the alternative representation
4287
// that always has a decimal point because JSON doesn't distinguish the
4288
// concepts of reals and integers.
4289
if (!isfinite(value)) {
4290
static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},
4291
{"null", "-1e+9999", "1e+9999"}};
4292
return reps[useSpecialFloats ? 0 : 1]
4293
[isnan(value) ? 0 : (value < 0) ? 1 : 2];
4294
}
4295
4296
String buffer(size_t(36), '\0');
4297
while (true) {
4298
int len = jsoncpp_snprintf(
4299
&*buffer.begin(), buffer.size(),
4300
(precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f",
4301
precision, value);
4302
assert(len >= 0);
4303
auto wouldPrint = static_cast<size_t>(len);
4304
if (wouldPrint >= buffer.size()) {
4305
buffer.resize(wouldPrint + 1);
4306
continue;
4307
}
4308
buffer.resize(wouldPrint);
4309
break;
4310
}
4311
4312
buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
4313
4314
// strip the zero padding from the right
4315
if (precisionType == PrecisionType::decimalPlaces) {
4316
buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end());
4317
}
4318
4319
// try to ensure we preserve the fact that this was given to us as a double on
4320
// input
4321
if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
4322
buffer += ".0";
4323
}
4324
return buffer;
4325
}
4326
} // namespace
4327
4328
String valueToString(double value,
4329
unsigned int precision,
4330
PrecisionType precisionType) {
4331
return valueToString(value, false, precision, precisionType);
4332
}
4333
4334
String valueToString(bool value) { return value ? "true" : "false"; }
4335
4336
static bool isAnyCharRequiredQuoting(char const* s, size_t n) {
4337
assert(s || !n);
4338
4339
char const* const end = s + n;
4340
for (char const* cur = s; cur < end; ++cur) {
4341
if (*cur == '\\' || *cur == '\"' || *cur < ' ' ||
4342
static_cast<unsigned char>(*cur) < 0x80)
4343
return true;
4344
}
4345
return false;
4346
}
4347
4348
static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
4349
const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;
4350
4351
unsigned int firstByte = static_cast<unsigned char>(*s);
4352
4353
if (firstByte < 0x80)
4354
return firstByte;
4355
4356
if (firstByte < 0xE0) {
4357
if (e - s < 2)
4358
return REPLACEMENT_CHARACTER;
4359
4360
unsigned int calculated =
4361
((firstByte & 0x1F) << 6) | (static_cast<unsigned int>(s[1]) & 0x3F);
4362
s += 1;
4363
// oversized encoded characters are invalid
4364
return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;
4365
}
4366
4367
if (firstByte < 0xF0) {
4368
if (e - s < 3)
4369
return REPLACEMENT_CHARACTER;
4370
4371
unsigned int calculated = ((firstByte & 0x0F) << 12) |
4372
((static_cast<unsigned int>(s[1]) & 0x3F) << 6) |
4373
(static_cast<unsigned int>(s[2]) & 0x3F);
4374
s += 2;
4375
// surrogates aren't valid codepoints itself
4376
// shouldn't be UTF-8 encoded
4377
if (calculated >= 0xD800 && calculated <= 0xDFFF)
4378
return REPLACEMENT_CHARACTER;
4379
// oversized encoded characters are invalid
4380
return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;
4381
}
4382
4383
if (firstByte < 0xF8) {
4384
if (e - s < 4)
4385
return REPLACEMENT_CHARACTER;
4386
4387
unsigned int calculated = ((firstByte & 0x07) << 18) |
4388
((static_cast<unsigned int>(s[1]) & 0x3F) << 12) |
4389
((static_cast<unsigned int>(s[2]) & 0x3F) << 6) |
4390
(static_cast<unsigned int>(s[3]) & 0x3F);
4391
s += 3;
4392
// oversized encoded characters are invalid
4393
return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;
4394
}
4395
4396
return REPLACEMENT_CHARACTER;
4397
}
4398
4399
static const char hex2[] = "000102030405060708090a0b0c0d0e0f"
4400
"101112131415161718191a1b1c1d1e1f"
4401
"202122232425262728292a2b2c2d2e2f"
4402
"303132333435363738393a3b3c3d3e3f"
4403
"404142434445464748494a4b4c4d4e4f"
4404
"505152535455565758595a5b5c5d5e5f"
4405
"606162636465666768696a6b6c6d6e6f"
4406
"707172737475767778797a7b7c7d7e7f"
4407
"808182838485868788898a8b8c8d8e8f"
4408
"909192939495969798999a9b9c9d9e9f"
4409
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
4410
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
4411
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
4412
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
4413
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
4414
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
4415
4416
static String toHex16Bit(unsigned int x) {
4417
const unsigned int hi = (x >> 8) & 0xff;
4418
const unsigned int lo = x & 0xff;
4419
String result(4, ' ');
4420
result[0] = hex2[2 * hi];
4421
result[1] = hex2[2 * hi + 1];
4422
result[2] = hex2[2 * lo];
4423
result[3] = hex2[2 * lo + 1];
4424
return result;
4425
}
4426
4427
static String valueToQuotedStringN(const char* value, unsigned length) {
4428
if (value == nullptr)
4429
return "";
4430
4431
if (!isAnyCharRequiredQuoting(value, length))
4432
return String("\"") + value + "\"";
4433
// We have to walk value and escape any special characters.
4434
// Appending to String is not efficient, but this should be rare.
4435
// (Note: forward slashes are *not* rare, but I am not escaping them.)
4436
String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL
4437
String result;
4438
result.reserve(maxsize); // to avoid lots of mallocs
4439
result += "\"";
4440
char const* end = value + length;
4441
for (const char* c = value; c != end; ++c) {
4442
switch (*c) {
4443
case '\"':
4444
result += "\\\"";
4445
break;
4446
case '\\':
4447
result += "\\\\";
4448
break;
4449
case '\b':
4450
result += "\\b";
4451
break;
4452
case '\f':
4453
result += "\\f";
4454
break;
4455
case '\n':
4456
result += "\\n";
4457
break;
4458
case '\r':
4459
result += "\\r";
4460
break;
4461
case '\t':
4462
result += "\\t";
4463
break;
4464
// case '/':
4465
// Even though \/ is considered a legal escape in JSON, a bare
4466
// slash is also legal, so I see no reason to escape it.
4467
// (I hope I am not misunderstanding something.)
4468
// blep notes: actually escaping \/ may be useful in javascript to avoid </
4469
// sequence.
4470
// Should add a flag to allow this compatibility mode and prevent this
4471
// sequence from occurring.
4472
default: {
4473
unsigned int cp = utf8ToCodepoint(c, end);
4474
// don't escape non-control characters
4475
// (short escape sequence are applied above)
4476
if (cp < 0x80 && cp >= 0x20)
4477
result += static_cast<char>(cp);
4478
else if (cp < 0x10000) { // codepoint is in Basic Multilingual Plane
4479
result += "\\u";
4480
result += toHex16Bit(cp);
4481
} else { // codepoint is not in Basic Multilingual Plane
4482
// convert to surrogate pair first
4483
cp -= 0x10000;
4484
result += "\\u";
4485
result += toHex16Bit((cp >> 10) + 0xD800);
4486
result += "\\u";
4487
result += toHex16Bit((cp & 0x3FF) + 0xDC00);
4488
}
4489
} break;
4490
}
4491
}
4492
result += "\"";
4493
return result;
4494
}
4495
4496
String valueToQuotedString(const char* value) {
4497
return valueToQuotedStringN(value, static_cast<unsigned int>(strlen(value)));
4498
}
4499
4500
// Class Writer
4501
// //////////////////////////////////////////////////////////////////
4502
Writer::~Writer() = default;
4503
4504
// Class FastWriter
4505
// //////////////////////////////////////////////////////////////////
4506
4507
FastWriter::FastWriter()
4508
4509
= default;
4510
4511
void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }
4512
4513
void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
4514
4515
void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
4516
4517
String FastWriter::write(const Value& root) {
4518
document_.clear();
4519
writeValue(root);
4520
if (!omitEndingLineFeed_)
4521
document_ += '\n';
4522
return document_;
4523
}
4524
4525
void FastWriter::writeValue(const Value& value) {
4526
switch (value.type()) {
4527
case nullValue:
4528
if (!dropNullPlaceholders_)
4529
document_ += "null";
4530
break;
4531
case intValue:
4532
document_ += valueToString(value.asLargestInt());
4533
break;
4534
case uintValue:
4535
document_ += valueToString(value.asLargestUInt());
4536
break;
4537
case realValue:
4538
document_ += valueToString(value.asDouble());
4539
break;
4540
case stringValue: {
4541
// Is NULL possible for value.string_? No.
4542
char const* str;
4543
char const* end;
4544
bool ok = value.getString(&str, &end);
4545
if (ok)
4546
document_ += valueToQuotedStringN(str, static_cast<unsigned>(end - str));
4547
break;
4548
}
4549
case booleanValue:
4550
document_ += valueToString(value.asBool());
4551
break;
4552
case arrayValue: {
4553
document_ += '[';
4554
ArrayIndex size = value.size();
4555
for (ArrayIndex index = 0; index < size; ++index) {
4556
if (index > 0)
4557
document_ += ',';
4558
writeValue(value[index]);
4559
}
4560
document_ += ']';
4561
} break;
4562
case objectValue: {
4563
Value::Members members(value.getMemberNames());
4564
document_ += '{';
4565
for (auto it = members.begin(); it != members.end(); ++it) {
4566
const String& name = *it;
4567
if (it != members.begin())
4568
document_ += ',';
4569
document_ += valueToQuotedStringN(name.data(),
4570
static_cast<unsigned>(name.length()));
4571
document_ += yamlCompatibilityEnabled_ ? ": " : ":";
4572
writeValue(value[name]);
4573
}
4574
document_ += '}';
4575
} break;
4576
}
4577
}
4578
4579
// Class StyledWriter
4580
// //////////////////////////////////////////////////////////////////
4581
4582
StyledWriter::StyledWriter() = default;
4583
4584
String StyledWriter::write(const Value& root) {
4585
document_.clear();
4586
addChildValues_ = false;
4587
indentString_.clear();
4588
writeCommentBeforeValue(root);
4589
writeValue(root);
4590
writeCommentAfterValueOnSameLine(root);
4591
document_ += '\n';
4592
return document_;
4593
}
4594
4595
void StyledWriter::writeValue(const Value& value) {
4596
switch (value.type()) {
4597
case nullValue:
4598
pushValue("null");
4599
break;
4600
case intValue:
4601
pushValue(valueToString(value.asLargestInt()));
4602
break;
4603
case uintValue:
4604
pushValue(valueToString(value.asLargestUInt()));
4605
break;
4606
case realValue:
4607
pushValue(valueToString(value.asDouble()));
4608
break;
4609
case stringValue: {
4610
// Is NULL possible for value.string_? No.
4611
char const* str;
4612
char const* end;
4613
bool ok = value.getString(&str, &end);
4614
if (ok)
4615
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
4616
else
4617
pushValue("");
4618
break;
4619
}
4620
case booleanValue:
4621
pushValue(valueToString(value.asBool()));
4622
break;
4623
case arrayValue:
4624
writeArrayValue(value);
4625
break;
4626
case objectValue: {
4627
Value::Members members(value.getMemberNames());
4628
if (members.empty())
4629
pushValue("{}");
4630
else {
4631
writeWithIndent("{");
4632
indent();
4633
auto it = members.begin();
4634
for (;;) {
4635
const String& name = *it;
4636
const Value& childValue = value[name];
4637
writeCommentBeforeValue(childValue);
4638
writeWithIndent(valueToQuotedString(name.c_str()));
4639
document_ += " : ";
4640
writeValue(childValue);
4641
if (++it == members.end()) {
4642
writeCommentAfterValueOnSameLine(childValue);
4643
break;
4644
}
4645
document_ += ',';
4646
writeCommentAfterValueOnSameLine(childValue);
4647
}
4648
unindent();
4649
writeWithIndent("}");
4650
}
4651
} break;
4652
}
4653
}
4654
4655
void StyledWriter::writeArrayValue(const Value& value) {
4656
unsigned size = value.size();
4657
if (size == 0)
4658
pushValue("[]");
4659
else {
4660
bool isArrayMultiLine = isMultilineArray(value);
4661
if (isArrayMultiLine) {
4662
writeWithIndent("[");
4663
indent();
4664
bool hasChildValue = !childValues_.empty();
4665
unsigned index = 0;
4666
for (;;) {
4667
const Value& childValue = value[index];
4668
writeCommentBeforeValue(childValue);
4669
if (hasChildValue)
4670
writeWithIndent(childValues_[index]);
4671
else {
4672
writeIndent();
4673
writeValue(childValue);
4674
}
4675
if (++index == size) {
4676
writeCommentAfterValueOnSameLine(childValue);
4677
break;
4678
}
4679
document_ += ',';
4680
writeCommentAfterValueOnSameLine(childValue);
4681
}
4682
unindent();
4683
writeWithIndent("]");
4684
} else // output on a single line
4685
{
4686
assert(childValues_.size() == size);
4687
document_ += "[ ";
4688
for (unsigned index = 0; index < size; ++index) {
4689
if (index > 0)
4690
document_ += ", ";
4691
document_ += childValues_[index];
4692
}
4693
document_ += " ]";
4694
}
4695
}
4696
}
4697
4698
bool StyledWriter::isMultilineArray(const Value& value) {
4699
ArrayIndex const size = value.size();
4700
bool isMultiLine = size * 3 >= rightMargin_;
4701
childValues_.clear();
4702
for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
4703
const Value& childValue = value[index];
4704
isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4705
!childValue.empty());
4706
}
4707
if (!isMultiLine) // check if line length > max line length
4708
{
4709
childValues_.reserve(size);
4710
addChildValues_ = true;
4711
ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4712
for (ArrayIndex index = 0; index < size; ++index) {
4713
if (hasCommentForValue(value[index])) {
4714
isMultiLine = true;
4715
}
4716
writeValue(value[index]);
4717
lineLength += static_cast<ArrayIndex>(childValues_[index].length());
4718
}
4719
addChildValues_ = false;
4720
isMultiLine = isMultiLine || lineLength >= rightMargin_;
4721
}
4722
return isMultiLine;
4723
}
4724
4725
void StyledWriter::pushValue(const String& value) {
4726
if (addChildValues_)
4727
childValues_.push_back(value);
4728
else
4729
document_ += value;
4730
}
4731
4732
void StyledWriter::writeIndent() {
4733
if (!document_.empty()) {
4734
char last = document_[document_.length() - 1];
4735
if (last == ' ') // already indented
4736
return;
4737
if (last != '\n') // Comments may add new-line
4738
document_ += '\n';
4739
}
4740
document_ += indentString_;
4741
}
4742
4743
void StyledWriter::writeWithIndent(const String& value) {
4744
writeIndent();
4745
document_ += value;
4746
}
4747
4748
void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); }
4749
4750
void StyledWriter::unindent() {
4751
assert(indentString_.size() >= indentSize_);
4752
indentString_.resize(indentString_.size() - indentSize_);
4753
}
4754
4755
void StyledWriter::writeCommentBeforeValue(const Value& root) {
4756
if (!root.hasComment(commentBefore))
4757
return;
4758
4759
document_ += '\n';
4760
writeIndent();
4761
const String& comment = root.getComment(commentBefore);
4762
String::const_iterator iter = comment.begin();
4763
while (iter != comment.end()) {
4764
document_ += *iter;
4765
if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
4766
writeIndent();
4767
++iter;
4768
}
4769
4770
// Comments are stripped of trailing newlines, so add one here
4771
document_ += '\n';
4772
}
4773
4774
void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4775
if (root.hasComment(commentAfterOnSameLine))
4776
document_ += " " + root.getComment(commentAfterOnSameLine);
4777
4778
if (root.hasComment(commentAfter)) {
4779
document_ += '\n';
4780
document_ += root.getComment(commentAfter);
4781
document_ += '\n';
4782
}
4783
}
4784
4785
bool StyledWriter::hasCommentForValue(const Value& value) {
4786
return value.hasComment(commentBefore) ||
4787
value.hasComment(commentAfterOnSameLine) ||
4788
value.hasComment(commentAfter);
4789
}
4790
4791
// Class StyledStreamWriter
4792
// //////////////////////////////////////////////////////////////////
4793
4794
StyledStreamWriter::StyledStreamWriter(String indentation)
4795
: document_(nullptr), indentation_(std::move(indentation)),
4796
addChildValues_(), indented_(false) {}
4797
4798
void StyledStreamWriter::write(OStream& out, const Value& root) {
4799
document_ = &out;
4800
addChildValues_ = false;
4801
indentString_.clear();
4802
indented_ = true;
4803
writeCommentBeforeValue(root);
4804
if (!indented_)
4805
writeIndent();
4806
indented_ = true;
4807
writeValue(root);
4808
writeCommentAfterValueOnSameLine(root);
4809
*document_ << "\n";
4810
document_ = nullptr; // Forget the stream, for safety.
4811
}
4812
4813
void StyledStreamWriter::writeValue(const Value& value) {
4814
switch (value.type()) {
4815
case nullValue:
4816
pushValue("null");
4817
break;
4818
case intValue:
4819
pushValue(valueToString(value.asLargestInt()));
4820
break;
4821
case uintValue:
4822
pushValue(valueToString(value.asLargestUInt()));
4823
break;
4824
case realValue:
4825
pushValue(valueToString(value.asDouble()));
4826
break;
4827
case stringValue: {
4828
// Is NULL possible for value.string_? No.
4829
char const* str;
4830
char const* end;
4831
bool ok = value.getString(&str, &end);
4832
if (ok)
4833
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
4834
else
4835
pushValue("");
4836
break;
4837
}
4838
case booleanValue:
4839
pushValue(valueToString(value.asBool()));
4840
break;
4841
case arrayValue:
4842
writeArrayValue(value);
4843
break;
4844
case objectValue: {
4845
Value::Members members(value.getMemberNames());
4846
if (members.empty())
4847
pushValue("{}");
4848
else {
4849
writeWithIndent("{");
4850
indent();
4851
auto it = members.begin();
4852
for (;;) {
4853
const String& name = *it;
4854
const Value& childValue = value[name];
4855
writeCommentBeforeValue(childValue);
4856
writeWithIndent(valueToQuotedString(name.c_str()));
4857
*document_ << " : ";
4858
writeValue(childValue);
4859
if (++it == members.end()) {
4860
writeCommentAfterValueOnSameLine(childValue);
4861
break;
4862
}
4863
*document_ << ",";
4864
writeCommentAfterValueOnSameLine(childValue);
4865
}
4866
unindent();
4867
writeWithIndent("}");
4868
}
4869
} break;
4870
}
4871
}
4872
4873
void StyledStreamWriter::writeArrayValue(const Value& value) {
4874
unsigned size = value.size();
4875
if (size == 0)
4876
pushValue("[]");
4877
else {
4878
bool isArrayMultiLine = isMultilineArray(value);
4879
if (isArrayMultiLine) {
4880
writeWithIndent("[");
4881
indent();
4882
bool hasChildValue = !childValues_.empty();
4883
unsigned index = 0;
4884
for (;;) {
4885
const Value& childValue = value[index];
4886
writeCommentBeforeValue(childValue);
4887
if (hasChildValue)
4888
writeWithIndent(childValues_[index]);
4889
else {
4890
if (!indented_)
4891
writeIndent();
4892
indented_ = true;
4893
writeValue(childValue);
4894
indented_ = false;
4895
}
4896
if (++index == size) {
4897
writeCommentAfterValueOnSameLine(childValue);
4898
break;
4899
}
4900
*document_ << ",";
4901
writeCommentAfterValueOnSameLine(childValue);
4902
}
4903
unindent();
4904
writeWithIndent("]");
4905
} else // output on a single line
4906
{
4907
assert(childValues_.size() == size);
4908
*document_ << "[ ";
4909
for (unsigned index = 0; index < size; ++index) {
4910
if (index > 0)
4911
*document_ << ", ";
4912
*document_ << childValues_[index];
4913
}
4914
*document_ << " ]";
4915
}
4916
}
4917
}
4918
4919
bool StyledStreamWriter::isMultilineArray(const Value& value) {
4920
ArrayIndex const size = value.size();
4921
bool isMultiLine = size * 3 >= rightMargin_;
4922
childValues_.clear();
4923
for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
4924
const Value& childValue = value[index];
4925
isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
4926
!childValue.empty());
4927
}
4928
if (!isMultiLine) // check if line length > max line length
4929
{
4930
childValues_.reserve(size);
4931
addChildValues_ = true;
4932
ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
4933
for (ArrayIndex index = 0; index < size; ++index) {
4934
if (hasCommentForValue(value[index])) {
4935
isMultiLine = true;
4936
}
4937
writeValue(value[index]);
4938
lineLength += static_cast<ArrayIndex>(childValues_[index].length());
4939
}
4940
addChildValues_ = false;
4941
isMultiLine = isMultiLine || lineLength >= rightMargin_;
4942
}
4943
return isMultiLine;
4944
}
4945
4946
void StyledStreamWriter::pushValue(const String& value) {
4947
if (addChildValues_)
4948
childValues_.push_back(value);
4949
else
4950
*document_ << value;
4951
}
4952
4953
void StyledStreamWriter::writeIndent() {
4954
// blep intended this to look at the so-far-written string
4955
// to determine whether we are already indented, but
4956
// with a stream we cannot do that. So we rely on some saved state.
4957
// The caller checks indented_.
4958
*document_ << '\n' << indentString_;
4959
}
4960
4961
void StyledStreamWriter::writeWithIndent(const String& value) {
4962
if (!indented_)
4963
writeIndent();
4964
*document_ << value;
4965
indented_ = false;
4966
}
4967
4968
void StyledStreamWriter::indent() { indentString_ += indentation_; }
4969
4970
void StyledStreamWriter::unindent() {
4971
assert(indentString_.size() >= indentation_.size());
4972
indentString_.resize(indentString_.size() - indentation_.size());
4973
}
4974
4975
void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
4976
if (!root.hasComment(commentBefore))
4977
return;
4978
4979
if (!indented_)
4980
writeIndent();
4981
const String& comment = root.getComment(commentBefore);
4982
String::const_iterator iter = comment.begin();
4983
while (iter != comment.end()) {
4984
*document_ << *iter;
4985
if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
4986
// writeIndent(); // would include newline
4987
*document_ << indentString_;
4988
++iter;
4989
}
4990
indented_ = false;
4991
}
4992
4993
void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
4994
if (root.hasComment(commentAfterOnSameLine))
4995
*document_ << ' ' << root.getComment(commentAfterOnSameLine);
4996
4997
if (root.hasComment(commentAfter)) {
4998
writeIndent();
4999
*document_ << root.getComment(commentAfter);
5000
}
5001
indented_ = false;
5002
}
5003
5004
bool StyledStreamWriter::hasCommentForValue(const Value& value) {
5005
return value.hasComment(commentBefore) ||
5006
value.hasComment(commentAfterOnSameLine) ||
5007
value.hasComment(commentAfter);
5008
}
5009
5010
//////////////////////////
5011
// BuiltStyledStreamWriter
5012
5013
/// Scoped enums are not available until C++11.
5014
struct CommentStyle {
5015
/// Decide whether to write comments.
5016
enum Enum {
5017
None, ///< Drop all comments.
5018
Most, ///< Recover odd behavior of previous versions (not implemented yet).
5019
All ///< Keep all comments.
5020
};
5021
};
5022
5023
struct BuiltStyledStreamWriter : public StreamWriter {
5024
BuiltStyledStreamWriter(String indentation,
5025
CommentStyle::Enum cs,
5026
String colonSymbol,
5027
String nullSymbol,
5028
String endingLineFeedSymbol,
5029
bool useSpecialFloats,
5030
unsigned int precision,
5031
PrecisionType precisionType);
5032
int write(Value const& root, OStream* sout) override;
5033
5034
private:
5035
void writeValue(Value const& value);
5036
void writeArrayValue(Value const& value);
5037
bool isMultilineArray(Value const& value);
5038
void pushValue(String const& value);
5039
void writeIndent();
5040
void writeWithIndent(String const& value);
5041
void indent();
5042
void unindent();
5043
void writeCommentBeforeValue(Value const& root);
5044
void writeCommentAfterValueOnSameLine(Value const& root);
5045
static bool hasCommentForValue(const Value& value);
5046
5047
typedef std::vector<String> ChildValues;
5048
5049
ChildValues childValues_;
5050
String indentString_;
5051
unsigned int rightMargin_;
5052
String indentation_;
5053
CommentStyle::Enum cs_;
5054
String colonSymbol_;
5055
String nullSymbol_;
5056
String endingLineFeedSymbol_;
5057
bool addChildValues_ : 1;
5058
bool indented_ : 1;
5059
bool useSpecialFloats_ : 1;
5060
unsigned int precision_;
5061
PrecisionType precisionType_;
5062
};
5063
BuiltStyledStreamWriter::BuiltStyledStreamWriter(String indentation,
5064
CommentStyle::Enum cs,
5065
String colonSymbol,
5066
String nullSymbol,
5067
String endingLineFeedSymbol,
5068
bool useSpecialFloats,
5069
unsigned int precision,
5070
PrecisionType precisionType)
5071
: rightMargin_(74), indentation_(std::move(indentation)), cs_(cs),
5072
colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)),
5073
endingLineFeedSymbol_(std::move(endingLineFeedSymbol)),
5074
addChildValues_(false), indented_(false),
5075
useSpecialFloats_(useSpecialFloats), precision_(precision),
5076
precisionType_(precisionType) {}
5077
int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) {
5078
sout_ = sout;
5079
addChildValues_ = false;
5080
indented_ = true;
5081
indentString_.clear();
5082
writeCommentBeforeValue(root);
5083
if (!indented_)
5084
writeIndent();
5085
indented_ = true;
5086
writeValue(root);
5087
writeCommentAfterValueOnSameLine(root);
5088
*sout_ << endingLineFeedSymbol_;
5089
sout_ = nullptr;
5090
return 0;
5091
}
5092
void BuiltStyledStreamWriter::writeValue(Value const& value) {
5093
switch (value.type()) {
5094
case nullValue:
5095
pushValue(nullSymbol_);
5096
break;
5097
case intValue:
5098
pushValue(valueToString(value.asLargestInt()));
5099
break;
5100
case uintValue:
5101
pushValue(valueToString(value.asLargestUInt()));
5102
break;
5103
case realValue:
5104
pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_,
5105
precisionType_));
5106
break;
5107
case stringValue: {
5108
// Is NULL is possible for value.string_? No.
5109
char const* str;
5110
char const* end;
5111
bool ok = value.getString(&str, &end);
5112
if (ok)
5113
pushValue(valueToQuotedStringN(str, static_cast<unsigned>(end - str)));
5114
else
5115
pushValue("");
5116
break;
5117
}
5118
case booleanValue:
5119
pushValue(valueToString(value.asBool()));
5120
break;
5121
case arrayValue:
5122
writeArrayValue(value);
5123
break;
5124
case objectValue: {
5125
Value::Members members(value.getMemberNames());
5126
if (members.empty())
5127
pushValue("{}");
5128
else {
5129
writeWithIndent("{");
5130
indent();
5131
auto it = members.begin();
5132
for (;;) {
5133
String const& name = *it;
5134
Value const& childValue = value[name];
5135
writeCommentBeforeValue(childValue);
5136
writeWithIndent(valueToQuotedStringN(
5137
name.data(), static_cast<unsigned>(name.length())));
5138
*sout_ << colonSymbol_;
5139
writeValue(childValue);
5140
if (++it == members.end()) {
5141
writeCommentAfterValueOnSameLine(childValue);
5142
break;
5143
}
5144
*sout_ << ",";
5145
writeCommentAfterValueOnSameLine(childValue);
5146
}
5147
unindent();
5148
writeWithIndent("}");
5149
}
5150
} break;
5151
}
5152
}
5153
5154
void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
5155
unsigned size = value.size();
5156
if (size == 0)
5157
pushValue("[]");
5158
else {
5159
bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);
5160
if (isMultiLine) {
5161
writeWithIndent("[");
5162
indent();
5163
bool hasChildValue = !childValues_.empty();
5164
unsigned index = 0;
5165
for (;;) {
5166
Value const& childValue = value[index];
5167
writeCommentBeforeValue(childValue);
5168
if (hasChildValue)
5169
writeWithIndent(childValues_[index]);
5170
else {
5171
if (!indented_)
5172
writeIndent();
5173
indented_ = true;
5174
writeValue(childValue);
5175
indented_ = false;
5176
}
5177
if (++index == size) {
5178
writeCommentAfterValueOnSameLine(childValue);
5179
break;
5180
}
5181
*sout_ << ",";
5182
writeCommentAfterValueOnSameLine(childValue);
5183
}
5184
unindent();
5185
writeWithIndent("]");
5186
} else // output on a single line
5187
{
5188
assert(childValues_.size() == size);
5189
*sout_ << "[";
5190
if (!indentation_.empty())
5191
*sout_ << " ";
5192
for (unsigned index = 0; index < size; ++index) {
5193
if (index > 0)
5194
*sout_ << ((!indentation_.empty()) ? ", " : ",");
5195
*sout_ << childValues_[index];
5196
}
5197
if (!indentation_.empty())
5198
*sout_ << " ";
5199
*sout_ << "]";
5200
}
5201
}
5202
}
5203
5204
bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) {
5205
ArrayIndex const size = value.size();
5206
bool isMultiLine = size * 3 >= rightMargin_;
5207
childValues_.clear();
5208
for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
5209
Value const& childValue = value[index];
5210
isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
5211
!childValue.empty());
5212
}
5213
if (!isMultiLine) // check if line length > max line length
5214
{
5215
childValues_.reserve(size);
5216
addChildValues_ = true;
5217
ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
5218
for (ArrayIndex index = 0; index < size; ++index) {
5219
if (hasCommentForValue(value[index])) {
5220
isMultiLine = true;
5221
}
5222
writeValue(value[index]);
5223
lineLength += static_cast<ArrayIndex>(childValues_[index].length());
5224
}
5225
addChildValues_ = false;
5226
isMultiLine = isMultiLine || lineLength >= rightMargin_;
5227
}
5228
return isMultiLine;
5229
}
5230
5231
void BuiltStyledStreamWriter::pushValue(String const& value) {
5232
if (addChildValues_)
5233
childValues_.push_back(value);
5234
else
5235
*sout_ << value;
5236
}
5237
5238
void BuiltStyledStreamWriter::writeIndent() {
5239
// blep intended this to look at the so-far-written string
5240
// to determine whether we are already indented, but
5241
// with a stream we cannot do that. So we rely on some saved state.
5242
// The caller checks indented_.
5243
5244
if (!indentation_.empty()) {
5245
// In this case, drop newlines too.
5246
*sout_ << '\n' << indentString_;
5247
}
5248
}
5249
5250
void BuiltStyledStreamWriter::writeWithIndent(String const& value) {
5251
if (!indented_)
5252
writeIndent();
5253
*sout_ << value;
5254
indented_ = false;
5255
}
5256
5257
void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
5258
5259
void BuiltStyledStreamWriter::unindent() {
5260
assert(indentString_.size() >= indentation_.size());
5261
indentString_.resize(indentString_.size() - indentation_.size());
5262
}
5263
5264
void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
5265
if (cs_ == CommentStyle::None)
5266
return;
5267
if (!root.hasComment(commentBefore))
5268
return;
5269
5270
if (!indented_)
5271
writeIndent();
5272
const String& comment = root.getComment(commentBefore);
5273
String::const_iterator iter = comment.begin();
5274
while (iter != comment.end()) {
5275
*sout_ << *iter;
5276
if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
5277
// writeIndent(); // would write extra newline
5278
*sout_ << indentString_;
5279
++iter;
5280
}
5281
indented_ = false;
5282
}
5283
5284
void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(
5285
Value const& root) {
5286
if (cs_ == CommentStyle::None)
5287
return;
5288
if (root.hasComment(commentAfterOnSameLine))
5289
*sout_ << " " + root.getComment(commentAfterOnSameLine);
5290
5291
if (root.hasComment(commentAfter)) {
5292
writeIndent();
5293
*sout_ << root.getComment(commentAfter);
5294
}
5295
}
5296
5297
// static
5298
bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
5299
return value.hasComment(commentBefore) ||
5300
value.hasComment(commentAfterOnSameLine) ||
5301
value.hasComment(commentAfter);
5302
}
5303
5304
///////////////
5305
// StreamWriter
5306
5307
StreamWriter::StreamWriter() : sout_(nullptr) {}
5308
StreamWriter::~StreamWriter() = default;
5309
StreamWriter::Factory::~Factory() = default;
5310
StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); }
5311
StreamWriterBuilder::~StreamWriterBuilder() = default;
5312
StreamWriter* StreamWriterBuilder::newStreamWriter() const {
5313
String indentation = settings_["indentation"].asString();
5314
String cs_str = settings_["commentStyle"].asString();
5315
String pt_str = settings_["precisionType"].asString();
5316
bool eyc = settings_["enableYAMLCompatibility"].asBool();
5317
bool dnp = settings_["dropNullPlaceholders"].asBool();
5318
bool usf = settings_["useSpecialFloats"].asBool();
5319
unsigned int pre = settings_["precision"].asUInt();
5320
CommentStyle::Enum cs = CommentStyle::All;
5321
if (cs_str == "All") {
5322
cs = CommentStyle::All;
5323
} else if (cs_str == "None") {
5324
cs = CommentStyle::None;
5325
} else {
5326
throwRuntimeError("commentStyle must be 'All' or 'None'");
5327
}
5328
PrecisionType precisionType(significantDigits);
5329
if (pt_str == "significant") {
5330
precisionType = PrecisionType::significantDigits;
5331
} else if (pt_str == "decimal") {
5332
precisionType = PrecisionType::decimalPlaces;
5333
} else {
5334
throwRuntimeError("precisionType must be 'significant' or 'decimal'");
5335
}
5336
String colonSymbol = " : ";
5337
if (eyc) {
5338
colonSymbol = ": ";
5339
} else if (indentation.empty()) {
5340
colonSymbol = ":";
5341
}
5342
String nullSymbol = "null";
5343
if (dnp) {
5344
nullSymbol.clear();
5345
}
5346
if (pre > 17)
5347
pre = 17;
5348
String endingLineFeedSymbol;
5349
return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol,
5350
endingLineFeedSymbol, usf, pre,
5351
precisionType);
5352
}
5353
static void getValidWriterKeys(std::set<String>* valid_keys) {
5354
valid_keys->clear();
5355
valid_keys->insert("indentation");
5356
valid_keys->insert("commentStyle");
5357
valid_keys->insert("enableYAMLCompatibility");
5358
valid_keys->insert("dropNullPlaceholders");
5359
valid_keys->insert("useSpecialFloats");
5360
valid_keys->insert("precision");
5361
valid_keys->insert("precisionType");
5362
}
5363
bool StreamWriterBuilder::validate(Json::Value* invalid) const {
5364
Json::Value my_invalid;
5365
if (!invalid)
5366
invalid = &my_invalid; // so we do not need to test for NULL
5367
Json::Value& inv = *invalid;
5368
std::set<String> valid_keys;
5369
getValidWriterKeys(&valid_keys);
5370
Value::Members keys = settings_.getMemberNames();
5371
size_t n = keys.size();
5372
for (size_t i = 0; i < n; ++i) {
5373
String const& key = keys[i];
5374
if (valid_keys.find(key) == valid_keys.end()) {
5375
inv[key] = settings_[key];
5376
}
5377
}
5378
return inv.empty();
5379
}
5380
Value& StreamWriterBuilder::operator[](const String& key) {
5381
return settings_[key];
5382
}
5383
// static
5384
void StreamWriterBuilder::setDefaults(Json::Value* settings) {
5385
//! [StreamWriterBuilderDefaults]
5386
(*settings)["commentStyle"] = "All";
5387
(*settings)["indentation"] = "\t";
5388
(*settings)["enableYAMLCompatibility"] = false;
5389
(*settings)["dropNullPlaceholders"] = false;
5390
(*settings)["useSpecialFloats"] = false;
5391
(*settings)["precision"] = 17;
5392
(*settings)["precisionType"] = "significant";
5393
//! [StreamWriterBuilderDefaults]
5394
}
5395
5396
String writeString(StreamWriter::Factory const& factory, Value const& root) {
5397
OStringStream sout;
5398
StreamWriterPtr const writer(factory.newStreamWriter());
5399
writer->write(root, &sout);
5400
return sout.str();
5401
}
5402
5403
OStream& operator<<(OStream& sout, Value const& root) {
5404
StreamWriterBuilder builder;
5405
StreamWriterPtr const writer(builder.newStreamWriter());
5406
writer->write(root, &sout);
5407
return sout;
5408
}
5409
5410
} // namespace Json
5411
5412
// //////////////////////////////////////////////////////////////////////
5413
// End of content of file: src/lib_json/json_writer.cpp
5414
// //////////////////////////////////////////////////////////////////////
5415
5416
5417
5418
5419
5420
5421