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