• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

open-source-parsers / jsoncpp / 27653199524

16 Jun 2026 10:47PM UTC coverage: 89.949% (-0.01%) from 89.959%
27653199524

Pull #1695

github

baylesj
fix: accept subnormal doubles when parsing (#1427)

decodeDouble parsed numbers via `istringstream >> double`. For a
subnormal value such as `3.2114e-312`, operator>> sets failbit (the
result underflowed) even though it produced the correctly-rounded value.
The failure path only special-cased overflow, so subnormals were
rejected as "not a number" -- meaning a value jsoncpp had just serialized
could fail to parse back.

In the failure path, accept the value when it is a subnormal
(std::fpclassify(value) == FP_SUBNORMAL). This keys off the value
operator>> produces, which is the correctly-rounded subnormal on
libstdc++, libc++, and MSVC, so it needs no errno/eof heuristics. It
deliberately does not accept results that round to zero, so malformed
numbers like "0e" / "0e+" (jsonchecker fail29/fail30) and other junk are
still rejected. Applied to both Reader and OurReader.

Adds CharReaderTest/parseSubnormal covering subnormals, a writer
round-trip, and continued rejection of malformed numbers.
Pull Request #1695: fix: accept subnormal and underflowing doubles when parsing (#1427)

2201 of 2614 branches covered (84.2%)

Branch coverage included in aggregate %.

1 of 2 new or added lines in 1 file covered. (50.0%)

16 existing lines in 1 file now uncovered.

2605 of 2729 relevant lines covered (95.46%)

23444.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.35
/src/lib_json/json_value.cpp
1
// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors
2
// Distributed under MIT license, or public domain if desired and
3
// recognized in your jurisdiction.
4
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5

6
#if !defined(JSON_IS_AMALGAMATION)
7
#include <json/assertions.h>
8
#include <json/value.h>
9
#include <json/writer.h>
10
#endif // if !defined(JSON_IS_AMALGAMATION)
11
#include <algorithm>
12
#include <cassert>
13
#include <cmath>
14
#include <cstddef>
15
#include <cstring>
16
#include <iostream>
17
#include <sstream>
18
#include <utility>
19

20
// Provide implementation equivalent of std::snprintf for older _MSC compilers
21
#if defined(_MSC_VER) && _MSC_VER < 1900
22
#include <stdarg.h>
23
static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size,
24
                                      const char* format, va_list ap) {
25
  int count = -1;
26
  if (size != 0)
27
    count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
28
  if (count == -1)
29
    count = _vscprintf(format, ap);
30
  return count;
31
}
32

33
int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
34
                                       const char* format, ...) {
35
  va_list ap;
36
  va_start(ap, format);
37
  const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);
38
  va_end(ap);
39
  return count;
40
}
41
#endif
42

43
// Disable warning C4702 : unreachable code
44
#if defined(_MSC_VER)
45
#pragma warning(disable : 4702)
46
#endif
47

48
#define JSON_ASSERT_UNREACHABLE assert(false)
49

50
namespace Json {
51
template <typename T>
52
static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
245,217✔
53
  std::unique_ptr<T> r;
245,217✔
54
  if (p) {
245,217✔
55
    r = std::unique_ptr<T>(new T(*p));
6✔
56
  }
57
  return r;
245,217✔
58
}
59

60
// This is a walkaround to avoid the static initialization of Value::null.
61
// kNull must be word-aligned to avoid crashing on ARM.  We use an alignment of
62
// 8 (instead of 4) as a bit of future-proofing.
63
#if defined(__ARMEL__)
64
#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
65
#else
66
#define ALIGNAS(byte_alignment)
67
#endif
68

69
// static
70
Value const& Value::nullSingleton() {
123,455✔
71
  static Value const nullStatic;
123,455!
72
  return nullStatic;
123,455✔
73
}
74

75
#if JSON_USE_NULLREF
76
// for backwards compatibility, we'll leave these global references around, but
77
// DO NOT use them in JSONCPP library code any more!
78
// static
79
Value const& Value::null = Value::nullSingleton();
80

81
// static
82
Value const& Value::nullRef = Value::nullSingleton();
83
#endif
84

85
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
86
template <typename T, typename U>
87
static inline bool InRange(double d, T min, U max) {
88
  // The casts can lose precision, but we are looking only for
89
  // an approximate range. Might fail on edge cases though. ~cdunn
90
  return d >= static_cast<double>(min) && d <= static_cast<double>(max) &&
91
         !(static_cast<U>(d) == min && d != static_cast<double>(min));
92
}
93
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
94
static inline double integerToDouble(Json::UInt64 value) {
95
  return static_cast<double>(Int64(value / 2)) * 2.0 +
21✔
96
         static_cast<double>(Int64(value & 1));
21✔
97
}
98

99
template <typename T> static inline double integerToDouble(T value) {
100
  return static_cast<double>(value);
101
}
102

103
template <typename T, typename U>
104
static inline bool InRange(double d, T min, U max) {
105
  return d >= integerToDouble(min) && d <= integerToDouble(max) &&
45!
106
         !(static_cast<U>(d) == min && d != integerToDouble(min));
34!
107
}
108
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
109

110
/** Duplicates the specified string value.
111
 * @param value Pointer to the string to duplicate. Must be zero-terminated if
112
 *              length is "unknown".
113
 * @param length Length of the value. if equals to unknown, then it will be
114
 *               computed using strlen(value).
115
 * @return Pointer on the duplicate instance of string.
116
 */
117
static inline char* duplicateStringValue(const char* value, size_t length) {
30,609✔
118
  // Avoid an integer overflow in the call to malloc below by limiting length
119
  // to a sane value.
120
  if (length >= static_cast<size_t>(Value::maxInt))
30,609✔
121
    length = Value::maxInt - 1;
122

123
  auto newString = static_cast<char*>(malloc(length + 1));
30,609✔
124
  if (newString == nullptr) {
30,609!
125
    throwRuntimeError("in Json::Value::duplicateStringValue(): "
×
126
                      "Failed to allocate string value buffer");
127
  }
128
  memcpy(newString, value, length);
129
  newString[length] = 0;
30,609✔
130
  return newString;
30,609✔
131
}
132

133
/* Record the length as a prefix.
134
 */
135
static inline char* duplicateAndPrefixStringValue(const char* value,
2,664✔
136
                                                  unsigned int length) {
137
  // Avoid an integer overflow in the call to malloc below by limiting length
138
  // to a sane value.
139
  JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -
2,664!
140
                                    sizeof(unsigned) - 1U,
141
                      "in Json::Value::duplicateAndPrefixStringValue(): "
142
                      "length too big for prefixing");
143
  size_t actualLength = sizeof(length) + length + 1;
2,664✔
144
  auto newString = static_cast<char*>(malloc(actualLength));
2,664✔
145
  if (newString == nullptr) {
2,664!
146
    throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
×
147
                      "Failed to allocate string value buffer");
148
  }
149
  *reinterpret_cast<unsigned*>(newString) = length;
2,664✔
150
  memcpy(newString + sizeof(unsigned), value, length);
2,664✔
151
  newString[actualLength - 1U] =
2,664✔
152
      0; // to avoid buffer over-run accidents by users later
153
  return newString;
2,664✔
154
}
155
inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
156
                                        unsigned* length, char const** value) {
157
  if (!isPrefixed) {
4,033!
158
    *length = static_cast<unsigned>(strlen(prefixed));
3✔
159
    *value = prefixed;
×
160
  } else {
161
    *length = *reinterpret_cast<unsigned const*>(prefixed);
4,166✔
162
    *value = prefixed + sizeof(unsigned);
4,030✔
163
  }
164
}
165
/** Free the string duplicated by
166
 * duplicateStringValue()/duplicateAndPrefixStringValue().
167
 */
168
#if JSONCPP_USE_SECURE_MEMORY
169
static inline void releasePrefixedStringValue(char* value) {
170
  unsigned length = 0;
171
  char const* valueDecoded;
172
  decodePrefixedString(true, value, &length, &valueDecoded);
173
  size_t const size = sizeof(unsigned) + length + 1U;
174
  memset(value, 0, size);
175
  free(value);
176
}
177
static inline void releaseStringValue(char* value, unsigned length) {
178
  // length==0 => we allocated the strings memory
179
  size_t size = (length == 0) ? strlen(value) : length;
180
  memset(value, 0, size);
181
  free(value);
182
}
183
#else  // !JSONCPP_USE_SECURE_MEMORY
184
static inline void releasePrefixedStringValue(char* value) { free(value); }
1✔
185
static inline void releaseStringValue(char* value, unsigned) { free(value); }
30,608✔
186
#endif // JSONCPP_USE_SECURE_MEMORY
187

188
} // namespace Json
189

190
// //////////////////////////////////////////////////////////////////
191
// //////////////////////////////////////////////////////////////////
192
// //////////////////////////////////////////////////////////////////
193
// ValueInternals...
194
// //////////////////////////////////////////////////////////////////
195
// //////////////////////////////////////////////////////////////////
196

197
namespace Json {
198

199
static const char* valueTypeToString(ValueType type) {
9✔
200
  switch (type) {
9!
201
  case nullValue:
202
    return "nullValue";
203
  case intValue:
3✔
204
    return "intValue";
3✔
205
  case uintValue:
×
206
    return "uintValue";
×
207
  case realValue:
×
208
    return "realValue";
×
209
  case stringValue:
3✔
210
    return "stringValue";
3✔
211
  case booleanValue:
×
212
    return "booleanValue";
×
213
  case arrayValue:
2✔
214
    return "arrayValue";
2✔
215
  case objectValue:
1✔
216
    return "objectValue";
1✔
217
  }
218
  return "unknown";
×
219
}
220

221
} // namespace Json
222
// //////////////////////////////////////////////////////////////////
223
#if !defined(JSON_IS_AMALGAMATION)
224

225
#include "json_valueiterator.inl"
226
#endif // if !defined(JSON_IS_AMALGAMATION)
227

228
namespace Json {
229

230
#if JSON_USE_EXCEPTION
231
Exception::Exception(String msg) : msg_(std::move(msg)) {}
49✔
232
Exception::~Exception() noexcept = default;
49✔
233
char const* Exception::what() const noexcept { return msg_.c_str(); }
6✔
234
RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
18✔
235
LogicError::LogicError(String const& msg) : Exception(msg) {}
80✔
236
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
9✔
237
  throw RuntimeError(msg);
9✔
238
}
239
JSONCPP_NORETURN void throwLogicError(String const& msg) {
40✔
240
  throw LogicError(msg);
40✔
241
}
242
#else // !JSON_USE_EXCEPTION
243
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
244
  std::cerr << msg << std::endl;
245
  abort();
246
}
247
JSONCPP_NORETURN void throwLogicError(String const& msg) {
248
  std::cerr << msg << std::endl;
249
  abort();
250
}
251
#endif
252

253
// //////////////////////////////////////////////////////////////////
254
// //////////////////////////////////////////////////////////////////
255
// //////////////////////////////////////////////////////////////////
256
// class Value::CZString
257
// //////////////////////////////////////////////////////////////////
258
// //////////////////////////////////////////////////////////////////
259
// //////////////////////////////////////////////////////////////////
260

261
// Notes: policy_ indicates if the string was allocated when
262
// a string is stored.
263

264
Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}
265,346✔
265

266
Value::CZString::CZString(char const* str, unsigned length,
36,717✔
267
                          DuplicationPolicy allocate)
36,717✔
268
    : cstr_(str) {
36,717✔
269
  // allocate != duplicate
270
  storage_.policy_ = allocate & 0x3;
36,717✔
271
  storage_.length_ = length & 0x3FFFFFFF;
36,717✔
272
}
36,717✔
273

274
Value::CZString::CZString(const CZString& other) {
244,915✔
275
  cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
188,095✔
276
               ? duplicateStringValue(other.cstr_, other.storage_.length_)
433,010✔
277
               : other.cstr_);
278
  if (other.cstr_) {
244,915✔
279
    storage_.policy_ =
30,612✔
280
        static_cast<unsigned>(
281
            other.cstr_
282
                ? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
30,612✔
283
                           noDuplication
284
                       ? noDuplication
30,612✔
285
                       : duplicate)
286
                : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
30,612✔
287
        3U;
288
    storage_.length_ = other.storage_.length_;
30,612✔
289
  } else {
290
    index_ = other.index_;
214,303✔
291
  }
292
}
244,915✔
293

294
Value::CZString::CZString(CZString&& other) noexcept : cstr_(other.cstr_) {
2✔
295
  if (other.cstr_) {
2✔
296
    storage_.policy_ = other.storage_.policy_;
1✔
297
    storage_.length_ = other.storage_.length_;
1✔
298
  } else {
299
    index_ = other.index_;
1✔
300
  }
301
  other.cstr_ = nullptr;
2✔
302
}
2✔
303

304
Value::CZString::~CZString() {
546,980✔
305
  if (cstr_ && storage_.policy_ == duplicate) {
546,980✔
306
    releaseStringValue(const_cast<char*>(cstr_),
307
                       storage_.length_ + 1U); // +1 for null terminating
308
                                               // character for sake of
309
                                               // completeness but not actually
310
                                               // necessary
311
  }
312
}
546,980✔
313

314
void Value::CZString::swap(CZString& other) {
×
315
  std::swap(cstr_, other.cstr_);
316
  std::swap(index_, other.index_);
317
}
×
318

319
Value::CZString& Value::CZString::operator=(const CZString& other) {
×
320
  cstr_ = other.cstr_;
×
321
  index_ = other.index_;
×
322
  return *this;
×
323
}
324

325
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
2✔
326
  if (cstr_ && storage_.policy_ == duplicate) {
2!
327
    releasePrefixedStringValue(const_cast<char*>(cstr_));
328
  }
329
  cstr_ = other.cstr_;
2✔
330
  if (other.cstr_) {
2✔
331
    storage_.policy_ = other.storage_.policy_;
1✔
332
    storage_.length_ = other.storage_.length_;
1✔
333
  } else {
334
    index_ = other.index_;
1✔
335
  }
336
  other.cstr_ = nullptr;
2✔
337
  return *this;
2✔
338
}
339

340
bool Value::CZString::operator<(const CZString& other) const {
3,942,357✔
341
  if (!cstr_)
3,942,357✔
342
    return index_ < other.index_;
3,782,662✔
343
  // return strcmp(cstr_, other.cstr_) < 0;
344
  // Assume both are strings.
345
  unsigned this_len = this->storage_.length_;
159,695✔
346
  unsigned other_len = other.storage_.length_;
159,695✔
347
  unsigned min_len = std::min<unsigned>(this_len, other_len);
159,695✔
348
  JSON_ASSERT(this->cstr_ && other.cstr_);
159,695!
349
  int comp = memcmp(this->cstr_, other.cstr_, min_len);
159,695✔
350
  if (comp < 0)
159,695✔
351
    return true;
352
  if (comp > 0)
81,450✔
353
    return false;
354
  return (this_len < other_len);
40,691✔
355
}
356

357
bool Value::CZString::operator==(const CZString& other) const {
120,444✔
358
  if (!cstr_)
120,444✔
359
    return index_ == other.index_;
104,939✔
360
  // return strcmp(cstr_, other.cstr_) == 0;
361
  // Assume both are strings.
362
  unsigned this_len = this->storage_.length_;
15,505✔
363
  unsigned other_len = other.storage_.length_;
15,505✔
364
  if (this_len != other_len)
15,505✔
365
    return false;
366
  JSON_ASSERT(this->cstr_ && other.cstr_);
5,420!
367
  int comp = memcmp(this->cstr_, other.cstr_, this_len);
5,420✔
368
  return comp == 0;
5,420✔
369
}
370

371
ArrayIndex Value::CZString::index() const { return index_; }
724✔
372

373
// const char* Value::CZString::c_str() const { return cstr_; }
374
const char* Value::CZString::data() const { return cstr_; }
1,736✔
375
unsigned Value::CZString::length() const { return storage_.length_; }
1,717✔
376
bool Value::CZString::isStaticString() const {
3✔
377
  return storage_.policy_ == noDuplication;
3✔
378
}
379

380
// //////////////////////////////////////////////////////////////////
381
// //////////////////////////////////////////////////////////////////
382
// //////////////////////////////////////////////////////////////////
383
// class Value::Value
384
// //////////////////////////////////////////////////////////////////
385
// //////////////////////////////////////////////////////////////////
386
// //////////////////////////////////////////////////////////////////
387

388
/*! \internal Default constructor initialization must be equivalent to:
389
 * memset( this, 0, sizeof(Value) )
390
 * This optimization is used in ValueInternalMap fast allocator.
391
 */
392
Value::Value(ValueType type) {
114,604✔
393
  static char const emptyString[] = "";
394
  initBasic(type);
114,604✔
395
  switch (type) {
114,604!
396
  case nullValue:
397
    break;
398
  case intValue:
2✔
399
  case uintValue:
400
    value_.int_ = 0;
2✔
401
    break;
2✔
402
  case realValue:
1✔
403
    value_.real_ = 0.0;
1✔
404
    break;
1✔
405
  case stringValue:
×
406
    // allocated_ == false, so this is safe.
407
    value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
×
408
    break;
×
409
  case arrayValue:
4,950✔
410
  case objectValue:
411
    value_.map_ = new ObjectValues();
4,950✔
412
    break;
4,950✔
413
  case booleanValue:
×
414
    value_.bool_ = false;
×
415
    break;
×
416
  default:
×
417
    JSON_ASSERT_UNREACHABLE;
×
418
  }
419
}
114,604✔
420

421
Value::Value(Int value) {
1,511✔
422
  initBasic(intValue);
1,511✔
423
  value_.int_ = value;
1,511✔
424
}
1,511✔
425

426
Value::Value(UInt value) {
216✔
427
  initBasic(uintValue);
216✔
428
  value_.uint_ = value;
216✔
429
}
216✔
430
#if defined(JSON_HAS_INT64)
431
Value::Value(Int64 value) {
105,108✔
432
  initBasic(intValue);
105,108✔
433
  value_.int_ = value;
105,108✔
434
}
105,108✔
435
Value::Value(UInt64 value) {
126✔
436
  initBasic(uintValue);
126✔
437
  value_.uint_ = value;
126✔
438
}
126✔
439
#endif // defined(JSON_HAS_INT64)
440

441
Value::Value(double value) {
592✔
442
  initBasic(realValue);
592✔
443
  value_.real_ = value;
592✔
444
}
592✔
445

446
Value::Value(const char* value) {
1,264✔
447
  initBasic(stringValue, true);
1,264✔
448
  JSON_ASSERT_MESSAGE(value != nullptr,
1,264!
449
                      "Null Value Passed to Value Constructor");
450
  value_.string_ = duplicateAndPrefixStringValue(
2,528✔
451
      value, static_cast<unsigned>(strlen(value)));
1,264✔
452
}
1,264✔
453

454
Value::Value(const char* begin, const char* end) {
2✔
455
  initBasic(stringValue, true);
2✔
456
  value_.string_ =
2✔
457
      duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
2✔
458
}
2✔
459

460
Value::Value(const String& value) {
1,259✔
461
  initBasic(stringValue, true);
1,259✔
462
  value_.string_ = duplicateAndPrefixStringValue(
1,259✔
463
      value.data(), static_cast<unsigned>(value.length()));
464
}
1,259✔
465

466
Value::Value(const StaticString& value) {
2✔
467
  initBasic(stringValue);
2✔
468
  value_.string_ = const_cast<char*>(value.c_str());
2✔
469
}
2✔
470

471
Value::Value(bool value) {
14,737✔
472
  initBasic(booleanValue);
14,737✔
473
  value_.bool_ = value;
14,737✔
474
}
14,737✔
475

476
Value::Value(const Value& other) {
245,209✔
477
  dupPayload(other);
245,209✔
478
  dupMeta(other);
245,209✔
479
}
245,209✔
480

481
Value::Value(Value&& other) noexcept {
55✔
482
  initBasic(nullValue);
55✔
483
  swap(other);
55✔
484
}
55✔
485

486
Value::~Value() {
484,685✔
487
  releasePayload();
484,685✔
488
  value_.uint_ = 0;
484,685✔
489
}
484,685✔
490

491
Value& Value::operator=(const Value& other) {
18✔
492
  Value(other).swap(*this);
18✔
493
  return *this;
18✔
494
}
495

496
Value& Value::operator=(Value&& other) noexcept {
125,181✔
497
  other.swap(*this);
125,181✔
498
  return *this;
125,181✔
499
}
500

501
void Value::swapPayload(Value& other) {
234,840✔
502
  std::swap(bits_, other.bits_);
503
  std::swap(value_, other.value_);
504
}
234,840✔
505

506
void Value::copyPayload(const Value& other) {
8✔
507
  releasePayload();
8✔
508
  dupPayload(other);
8✔
509
}
8✔
510

511
void Value::swap(Value& other) {
125,255✔
512
  swapPayload(other);
125,255✔
513
  std::swap(comments_, other.comments_);
125,255✔
514
  std::swap(start_, other.start_);
515
  std::swap(limit_, other.limit_);
516
}
125,255✔
517

518
void Value::copy(const Value& other) {
8✔
519
  copyPayload(other);
8✔
520
  dupMeta(other);
8✔
521
}
8✔
522

523
ValueType Value::type() const {
2,230,319✔
524
  return static_cast<ValueType>(bits_.value_type_);
2,230,319✔
525
}
526

527
int Value::compare(const Value& other) const {
120✔
528
  if (*this < other)
120✔
529
    return -1;
530
  if (*this > other)
89✔
531
    return 1;
31✔
532
  return 0;
533
}
534

535
bool Value::operator<(const Value& other) const {
1,279✔
536
  int typeDelta = type() - other.type();
1,279✔
537
  if (typeDelta)
1,279✔
538
    return typeDelta < 0;
77✔
539
  switch (type()) {
1,202!
540
  case nullValue:
541
    return false;
542
  case intValue:
564✔
543
    return value_.int_ < other.value_.int_;
564✔
544
  case uintValue:
34✔
545
    return value_.uint_ < other.value_.uint_;
34✔
546
  case realValue:
46✔
547
    return value_.real_ < other.value_.real_;
46✔
548
  case booleanValue:
35✔
549
    return value_.bool_ < other.value_.bool_;
35✔
550
  case stringValue: {
175✔
551
    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
175!
552
      return other.value_.string_ != nullptr;
×
553
    }
554
    unsigned this_len;
555
    unsigned other_len;
556
    char const* this_str;
557
    char const* other_str;
558
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
559
                         &this_str);
560
    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
561
                         &other_str);
562
    unsigned min_len = std::min<unsigned>(this_len, other_len);
175✔
563
    JSON_ASSERT(this_str && other_str);
564
    int comp = memcmp(this_str, other_str, min_len);
175✔
565
    if (comp < 0)
175✔
566
      return true;
567
    if (comp > 0)
163✔
568
      return false;
569
    return (this_len < other_len);
153✔
570
  }
571
  case arrayValue:
312✔
572
  case objectValue: {
573
    auto thisSize = value_.map_->size();
312✔
574
    auto otherSize = other.value_.map_->size();
312✔
575
    if (thisSize != otherSize)
312✔
576
      return thisSize < otherSize;
66✔
577
    return (*value_.map_) < (*other.value_.map_);
246✔
578
  }
579
  default:
×
580
    JSON_ASSERT_UNREACHABLE;
×
581
  }
582
  return false; // unreachable
583
}
584

585
bool Value::operator<=(const Value& other) const { return !(other < *this); }
120✔
586

587
bool Value::operator>=(const Value& other) const { return !(*this < other); }
120✔
588

589
bool Value::operator>(const Value& other) const { return other < *this; }
209✔
590

591
bool Value::operator==(const Value& other) const {
318✔
592
  if (type() != other.type())
318✔
593
    return false;
594
  switch (type()) {
303!
595
  case nullValue:
596
    return true;
597
  case intValue:
80✔
598
    return value_.int_ == other.value_.int_;
80✔
599
  case uintValue:
10✔
600
    return value_.uint_ == other.value_.uint_;
10✔
601
  case realValue:
14✔
602
    return value_.real_ == other.value_.real_;
14✔
603
  case booleanValue:
15✔
604
    return value_.bool_ == other.value_.bool_;
15✔
605
  case stringValue: {
91✔
606
    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
91!
607
      return (value_.string_ == other.value_.string_);
×
608
    }
609
    unsigned this_len;
610
    unsigned other_len;
611
    char const* this_str;
612
    char const* other_str;
613
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
614
                         &this_str);
615
    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
616
                         &other_str);
617
    if (this_len != other_len)
91✔
618
      return false;
619
    JSON_ASSERT(this_str && other_str);
620
    int comp = memcmp(this_str, other_str, this_len);
84✔
621
    return comp == 0;
84✔
622
  }
623
  case arrayValue:
60✔
624
  case objectValue:
625
    return value_.map_->size() == other.value_.map_->size() &&
107✔
626
           (*value_.map_) == (*other.value_.map_);
627
  default:
×
628
    JSON_ASSERT_UNREACHABLE;
×
629
  }
630
  return false; // unreachable
631
}
632

633
bool Value::operator!=(const Value& other) const { return !(*this == other); }
136✔
634

635
const char* Value::asCString() const {
4✔
636
  JSON_ASSERT_MESSAGE(type() == stringValue,
6✔
637
                      "in Json::Value::asCString(): requires stringValue");
638
  if (value_.string_ == nullptr)
3!
639
    return nullptr;
640
  unsigned this_len;
641
  char const* this_str;
642
  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
643
                       &this_str);
644
  return this_str;
645
}
646

647
#if JSONCPP_USE_SECURE_MEMORY
648
unsigned Value::getCStringLength() const {
649
  JSON_ASSERT_MESSAGE(type() == stringValue,
650
                      "in Json::Value::asCString(): requires stringValue");
651
  if (value_.string_ == 0)
652
    return 0;
653
  unsigned this_len;
654
  char const* this_str;
655
  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
656
                       &this_str);
657
  return this_len;
658
}
659
#endif
660

661
bool Value::getString(char const** begin, char const** end) const {
782✔
662
  if (type() != stringValue)
782!
663
    return false;
664
  if (value_.string_ == nullptr)
782!
665
    return false;
666
  unsigned length;
667
  decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
668
                       begin);
669
  *end = *begin + length;
782✔
670
  return true;
782✔
671
}
672

673
String Value::asString() const {
2,758✔
674
  switch (type()) {
2,758!
675
  case nullValue:
676
    return "";
2✔
677
  case stringValue: {
2,716✔
678
    if (value_.string_ == nullptr)
2,716!
679
      return "";
×
680
    unsigned this_len;
681
    char const* this_str;
682
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
683
                         &this_str);
684
    return String(this_str, this_len);
2,716✔
685
  }
686
  case booleanValue:
687
    return value_.bool_ ? "true" : "false";
×
688
  case intValue:
13✔
689
    return valueToString(value_.int_);
13✔
690
  case uintValue:
7✔
691
    return valueToString(value_.uint_);
7✔
692
  case realValue:
18✔
693
    return valueToString(value_.real_);
18✔
694
  default:
2✔
695
    JSON_FAIL_MESSAGE("Type is not convertible to string");
6✔
696
  }
697
}
698

699
Value::Int Value::asInt() const {
30✔
700
  switch (type()) {
30✔
701
  case intValue:
11✔
702
    JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
11!
703
    return Int(value_.int_);
11✔
704
  case uintValue:
8✔
705
    JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
8!
706
    return Int(value_.uint_);
8✔
707
  case realValue:
5✔
708
    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
5!
709
                        "double out of Int range");
710
    return Int(value_.real_);
711
  case nullValue:
712
    return 0;
713
  case booleanValue:
2✔
714
    return value_.bool_ ? 1 : 0;
2✔
715
  default:
716
    break;
717
  }
718
  JSON_FAIL_MESSAGE("Value is not convertible to Int.");
9✔
719
}
720

721
Value::UInt Value::asUInt() const {
1,585✔
722
  switch (type()) {
1,585✔
723
  case intValue:
1,568✔
724
    JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
1,568!
725
    return UInt(value_.int_);
1,568✔
726
  case uintValue:
6✔
727
    JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
6!
728
    return UInt(value_.uint_);
6✔
729
  case realValue:
5✔
730
    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt),
5!
731
                        "double out of UInt range");
732
    return UInt(value_.real_);
733
  case nullValue:
734
    return 0;
735
  case booleanValue:
2✔
736
    return value_.bool_ ? 1 : 0;
2✔
737
  default:
738
    break;
739
  }
740
  JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
9✔
741
}
742

743
#if defined(JSON_HAS_INT64)
744

745
Value::Int64 Value::asInt64() const {
157,460✔
746
  switch (type()) {
157,460✔
747
  case intValue:
157,438✔
748
    return Int64(value_.int_);
157,438✔
749
  case uintValue:
6✔
750
    JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
6!
751
    return Int64(value_.uint_);
6✔
752
  case realValue:
10✔
753
    // If the double value is in proximity to minInt64, it will be rounded to
754
    // minInt64. The correct value in this scenario is indeterminable
755
    JSON_ASSERT_MESSAGE(
10!
756
        value_.real_ != minInt64,
757
        "Double value is minInt64, precise value cannot be determined");
758
    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
×
759
                        "double out of Int64 range");
760
    return Int64(value_.real_);
761
  case nullValue:
762
    return 0;
763
  case booleanValue:
2✔
764
    return value_.bool_ ? 1 : 0;
2✔
765
  default:
766
    break;
767
  }
768
  JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
9✔
769
}
770

771
Value::UInt64 Value::asUInt64() const {
261✔
772
  switch (type()) {
261✔
773
  case intValue:
8✔
774
    JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
8!
775
    return UInt64(value_.int_);
8✔
776
  case uintValue:
237✔
777
    return UInt64(value_.uint_);
237✔
778
  case realValue:
10✔
779
    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0u, maxUInt64),
10!
780
                        "double out of UInt64 range");
781
    return UInt64(value_.real_);
782
  case nullValue:
783
    return 0;
784
  case booleanValue:
2✔
785
    return value_.bool_ ? 1 : 0;
2✔
786
  default:
787
    break;
788
  }
789
  JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
9✔
790
}
791
#endif // if defined(JSON_HAS_INT64)
792

793
LargestInt Value::asLargestInt() const {
157,448✔
794
#if defined(JSON_NO_INT64)
795
  return asInt();
796
#else
797
  return asInt64();
157,448✔
798
#endif
799
}
800

801
LargestUInt Value::asLargestUInt() const {
248✔
802
#if defined(JSON_NO_INT64)
803
  return asUInt();
804
#else
805
  return asUInt64();
248✔
806
#endif
807
}
808

809
double Value::asDouble() const {
533✔
810
  switch (type()) {
533✔
811
  case intValue:
20✔
812
    return static_cast<double>(value_.int_);
20✔
813
  case uintValue:
14✔
814
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
815
    return static_cast<double>(value_.uint_);
816
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
817
    return integerToDouble(value_.uint_);
14✔
818
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
819
  case realValue:
493✔
820
    return value_.real_;
493✔
821
  case nullValue:
822
    return 0.0;
823
  case booleanValue:
2✔
824
    return value_.bool_ ? 1.0 : 0.0;
2✔
825
  default:
826
    break;
827
  }
828
  JSON_FAIL_MESSAGE("Value is not convertible to double.");
9✔
829
}
830

831
float Value::asFloat() const {
40✔
832
  switch (type()) {
40✔
833
  case intValue:
10✔
834
    return static_cast<float>(value_.int_);
10✔
835
  case uintValue:
7✔
836
#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
837
    return static_cast<float>(value_.uint_);
838
#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
839
    // This can fail (silently?) if the value is bigger than MAX_FLOAT.
840
    return static_cast<float>(integerToDouble(value_.uint_));
7✔
841
#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
842
  case realValue:
17✔
843
    return static_cast<float>(value_.real_);
17✔
844
  case nullValue:
845
    return 0.0;
846
  case booleanValue:
2✔
847
    return value_.bool_ ? 1.0F : 0.0F;
2✔
848
  default:
849
    break;
850
  }
851
  JSON_FAIL_MESSAGE("Value is not convertible to float.");
9✔
852
}
853

854
bool Value::asBool() const {
12,772✔
855
  switch (type()) {
12,772!
856
  case booleanValue:
12,739✔
857
    return value_.bool_;
12,739✔
858
  case nullValue:
859
    return false;
860
  case intValue:
10✔
861
    return value_.int_ != 0;
10✔
862
  case uintValue:
7✔
863
    return value_.uint_ != 0;
7✔
864
  case realValue: {
13✔
865
    // According to JavaScript language zero or NaN is regarded as false
866
    const auto value_classification = std::fpclassify(value_.real_);
13!
867
    return value_classification != FP_ZERO && value_classification != FP_NAN;
13✔
868
  }
869
  default:
870
    break;
871
  }
872
  JSON_FAIL_MESSAGE("Value is not convertible to bool.");
9✔
873
}
874

875
bool Value::isConvertibleTo(ValueType other) const {
173✔
876
  switch (other) {
173!
877
  case nullValue:
39✔
878
    return (isNumeric() && asDouble() == 0.0) ||
102✔
879
           (type() == booleanValue && !value_.bool_) ||
67✔
880
           (type() == stringValue && asString().empty()) ||
105!
881
           (type() == arrayValue && value_.map_->empty()) ||
63✔
882
           (type() == objectValue && value_.map_->empty()) ||
100✔
883
           type() == nullValue;
29✔
884
  case intValue:
35✔
885
    return isInt() ||
58✔
886
           (type() == realValue && InRange(value_.real_, minInt, maxInt)) ||
54✔
887
           type() == booleanValue || type() == nullValue;
76✔
888
  case uintValue:
35✔
889
    return isUInt() ||
59✔
890
           (type() == realValue && InRange(value_.real_, 0u, maxUInt)) ||
56✔
891
           type() == booleanValue || type() == nullValue;
78✔
892
  case realValue:
13✔
893
    return isNumeric() || type() == booleanValue || type() == nullValue;
13✔
894
  case booleanValue:
12✔
895
    return isNumeric() || type() == booleanValue || type() == nullValue;
12✔
896
  case stringValue:
13✔
897
    return isNumeric() || type() == booleanValue || type() == stringValue ||
16✔
898
           type() == nullValue;
3✔
899
  case arrayValue:
13✔
900
    return type() == arrayValue || type() == nullValue;
13✔
901
  case objectValue:
13✔
902
    return type() == objectValue || type() == nullValue;
13✔
903
  }
904
  JSON_ASSERT_UNREACHABLE;
×
905
  return false;
906
}
907

908
/// Number of values in array or object
909
ArrayIndex Value::size() const {
845✔
910
  switch (type()) {
845!
911
  case nullValue:
912
  case intValue:
913
  case uintValue:
914
  case realValue:
915
  case booleanValue:
916
  case stringValue:
917
    return 0;
918
  case arrayValue: // size of the array is highest index + 1
804✔
919
    if (!value_.map_->empty()) {
804✔
920
      ObjectValues::const_iterator itLast = value_.map_->end();
921
      --itLast;
922
      return (*itLast).first.index() + 1;
717✔
923
    }
924
    return 0;
925
  case objectValue:
28✔
926
    return ArrayIndex(value_.map_->size());
28✔
927
  }
928
  JSON_ASSERT_UNREACHABLE;
×
929
  return 0; // unreachable;
930
}
931

932
bool Value::empty() const {
36✔
933
  if (isNull() || isArray() || isObject())
36!
934
    return size() == 0U;
36✔
935
  return false;
936
}
937

938
Value::operator bool() const { return !isNull(); }
4✔
939

940
void Value::clear() {
3✔
941
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
5!
942
                          type() == objectValue,
943
                      "in Json::Value::clear(): requires complex value");
944
  start_ = 0;
2✔
945
  limit_ = 0;
2✔
946
  switch (type()) {
2!
947
  case arrayValue:
2✔
948
  case objectValue:
949
    value_.map_->clear();
2✔
950
    break;
951
  default:
952
    break;
953
  }
954
}
2✔
955

956
void Value::resize(ArrayIndex newSize) {
7✔
957
  JSON_ASSERT_MESSAGE(
16✔
958
      type() == nullValue || type() == arrayValue,
959
      "in Json::Value::resize(): requires arrayValue, but found "
960
          << valueTypeToString(type()));
961
  if (type() == nullValue)
4✔
962
    *this = Value(arrayValue);
1✔
963
  ArrayIndex oldSize = size();
4✔
964
  if (newSize == 0)
4✔
965
    clear();
1✔
966
  else if (newSize > oldSize)
3✔
967
    for (ArrayIndex i = oldSize; i < newSize; ++i)
17✔
968
      (*this)[i];
15✔
969
  else {
970
    for (ArrayIndex index = newSize; index < oldSize; ++index) {
11✔
971
      value_.map_->erase(index);
20✔
972
    }
973
    JSON_ASSERT(size() == newSize);
1!
974
  }
975
}
4✔
976

977
Value& Value::operator[](ArrayIndex index) {
212,056✔
978
  JSON_ASSERT_MESSAGE(
212,062✔
979
      type() == nullValue || type() == arrayValue,
980
      "in Json::Value::operator[](ArrayIndex): requires arrayValue");
981
  if (type() == nullValue)
212,053✔
982
    *this = Value(arrayValue);
16✔
983
  CZString key(index);
212,053✔
984
  auto it = value_.map_->lower_bound(key);
212,053✔
985
  if (it != value_.map_->end() && (*it).first == key)
212,053✔
986
    return (*it).second;
104,914✔
987

988
  ObjectValues::value_type defaultValue(key, nullSingleton());
107,139✔
989
  it = value_.map_->insert(it, defaultValue);
107,139✔
990
  return (*it).second;
107,139✔
991
}
212,053✔
992

993
Value& Value::operator[](int index) {
107,048✔
994
  JSON_ASSERT_MESSAGE(
107,048!
995
      index >= 0,
996
      "in Json::Value::operator[](int index): index cannot be negative");
997
  return (*this)[ArrayIndex(index)];
107,048✔
998
}
999

1000
const Value& Value::operator[](ArrayIndex index) const {
53,225✔
1001
  JSON_ASSERT_MESSAGE(
53,225!
1002
      type() == nullValue || type() == arrayValue,
1003
      "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
1004
  if (type() == nullValue)
53,225!
UNCOV
1005
    return nullSingleton();
×
1006
  CZString key(index);
53,225✔
1007
  ObjectValues::const_iterator it = value_.map_->find(key);
53,225✔
1008
  if (it == value_.map_->end())
53,225✔
1009
    return nullSingleton();
1✔
1010
  return (*it).second;
53,224✔
1011
}
53,225✔
1012

1013
const Value& Value::operator[](int index) const {
4✔
1014
  JSON_ASSERT_MESSAGE(
4!
1015
      index >= 0,
1016
      "in Json::Value::operator[](int index) const: index cannot be negative");
1017
  return (*this)[ArrayIndex(index)];
4✔
1018
}
1019

1020
void Value::initBasic(ValueType type, bool allocated) {
239,476✔
1021
  setType(type);
1022
  setIsAllocated(allocated);
1023
  comments_ = Comments{};
239,476✔
1024
  start_ = 0;
239,476✔
1025
  limit_ = 0;
239,476✔
1026
}
239,476✔
1027

1028
void Value::dupPayload(const Value& other) {
245,217✔
1029
  setType(other.type());
245,217✔
1030
  setIsAllocated(false);
1031
  switch (type()) {
245,217!
1032
  case nullValue:
245,023✔
1033
  case intValue:
1034
  case uintValue:
1035
  case realValue:
1036
  case booleanValue:
1037
    value_ = other.value_;
245,023✔
1038
    break;
245,023✔
1039
  case stringValue:
139✔
1040
    if (other.value_.string_ && other.isAllocated()) {
139!
1041
      unsigned len;
1042
      char const* str;
1043
      decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
1044
                           &str);
1045
      value_.string_ = duplicateAndPrefixStringValue(str, len);
139✔
1046
      setIsAllocated(true);
1047
    } else {
UNCOV
1048
      value_.string_ = other.value_.string_;
×
1049
    }
1050
    break;
1051
  case arrayValue:
55✔
1052
  case objectValue:
1053
    value_.map_ = new ObjectValues(*other.value_.map_);
55✔
1054
    break;
55✔
UNCOV
1055
  default:
×
UNCOV
1056
    JSON_ASSERT_UNREACHABLE;
×
1057
  }
1058
}
245,217✔
1059

1060
void Value::releasePayload() {
484,693✔
1061
  switch (type()) {
484,693!
1062
  case nullValue:
1063
  case intValue:
1064
  case uintValue:
1065
  case realValue:
1066
  case booleanValue:
1067
    break;
1068
  case stringValue:
1069
    if (isAllocated())
2,666✔
1070
      releasePrefixedStringValue(value_.string_);
2,664✔
1071
    break;
1072
  case arrayValue:
5,005✔
1073
  case objectValue:
1074
    delete value_.map_;
10,010!
1075
    break;
UNCOV
1076
  default:
×
UNCOV
1077
    JSON_ASSERT_UNREACHABLE;
×
1078
  }
1079
}
484,693✔
1080

1081
void Value::dupMeta(const Value& other) {
245,217✔
1082
  comments_ = other.comments_;
245,217✔
1083
  start_ = other.start_;
245,217✔
1084
  limit_ = other.limit_;
245,217✔
1085
}
245,217✔
1086

1087
// Access an object value by name, create a null member if it does not exist.
1088
// @pre Type of '*this' is object or null.
1089
// @param key is null-terminated.
1090
Value& Value::resolveReference(const char* key) {
1✔
1091
  JSON_ASSERT_MESSAGE(
1!
1092
      type() == nullValue || type() == objectValue,
1093
      "in Json::Value::resolveReference(): requires objectValue, but found "
1094
          << valueTypeToString(type()));
1095
  if (type() == nullValue)
1!
1096
    *this = Value(objectValue);
1✔
1097
  CZString actualKey(key, static_cast<unsigned>(strlen(key)),
1✔
1098
                     CZString::noDuplication); // NOTE!
1✔
1099
  auto it = value_.map_->lower_bound(actualKey);
1✔
1100
  if (it != value_.map_->end() && (*it).first == actualKey)
1!
UNCOV
1101
    return (*it).second;
×
1102

1103
  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
1✔
1104
  it = value_.map_->insert(it, defaultValue);
1✔
1105
  Value& value = (*it).second;
1✔
1106
  return value;
1107
}
1✔
1108

1109
// @param key is not null-terminated.
1110
Value& Value::resolveReference(char const* key, char const* end) {
19,657✔
1111
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
19,666✔
1112
                      "in Json::Value::resolveReference(key, end): requires "
1113
                      "objectValue, but found "
1114
                          << valueTypeToString(type()));
1115
  if (type() == nullValue)
19,654✔
1116
    *this = Value(objectValue);
1,697✔
1117
  CZString actualKey(key, static_cast<unsigned>(end - key),
19,654✔
1118
                     CZString::duplicateOnCopy);
19,654✔
1119
  auto it = value_.map_->lower_bound(actualKey);
19,654✔
1120
  if (it != value_.map_->end() && (*it).first == actualKey)
19,654✔
1121
    return (*it).second;
4,370✔
1122

1123
  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
15,284✔
1124
  it = value_.map_->insert(it, defaultValue);
15,284✔
1125
  Value& value = (*it).second;
15,284✔
1126
  return value;
1127
}
19,654✔
1128

1129
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
6✔
1130
  const Value* value = &((*this)[index]);
6✔
1131
  return value == &nullSingleton() ? defaultValue : *value;
11✔
1132
}
1133

1134
bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
7✔
1135

1136
Value const* Value::find(char const* begin, char const* end) const {
17,050✔
1137
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
17,050!
1138
                      "in Json::Value::find(begin, end): requires "
1139
                      "objectValue or nullValue");
1140
  if (type() == nullValue)
17,050!
1141
    return nullptr;
1142
  CZString actualKey(begin, static_cast<unsigned>(end - begin),
17,050✔
1143
                     CZString::noDuplication);
17,050✔
1144
  ObjectValues::const_iterator it = value_.map_->find(actualKey);
17,050✔
1145
  if (it == value_.map_->end())
17,050✔
1146
    return nullptr;
1147
  return &(*it).second;
17,035✔
1148
}
17,050✔
1149
Value const* Value::find(const String& key) const {
896✔
1150
  return find(key.data(), key.data() + key.length());
896✔
1151
}
1152

1153
Value const* Value::findNull(const String& key) const {
2✔
1154
  return findValue<Value, &Value::isNull>(key);
2✔
1155
}
1156
Value const* Value::findBool(const String& key) const {
2✔
1157
  return findValue<Value, &Value::isBool>(key);
2✔
1158
}
1159
Value const* Value::findInt(const String& key) const {
2✔
1160
  return findValue<Value, &Value::isInt>(key);
2✔
1161
}
1162
Value const* Value::findInt64(const String& key) const {
2✔
1163
  return findValue<Value, &Value::isInt64>(key);
2✔
1164
}
1165
Value const* Value::findUInt(const String& key) const {
2✔
1166
  return findValue<Value, &Value::isUInt>(key);
2✔
1167
}
1168
Value const* Value::findUInt64(const String& key) const {
2✔
1169
  return findValue<Value, &Value::isUInt64>(key);
2✔
1170
}
1171
Value const* Value::findIntegral(const String& key) const {
2✔
1172
  return findValue<Value, &Value::isIntegral>(key);
2✔
1173
}
1174
Value const* Value::findDouble(const String& key) const {
2✔
1175
  return findValue<Value, &Value::isDouble>(key);
2✔
1176
}
1177
Value const* Value::findNumeric(const String& key) const {
2✔
1178
  return findValue<Value, &Value::isNumeric>(key);
2✔
1179
}
1180
Value const* Value::findString(const String& key) const {
2✔
1181
  return findValue<Value, &Value::isString>(key);
2✔
1182
}
1183
Value const* Value::findArray(const String& key) const {
2✔
1184
  return findValue<Value, &Value::isArray>(key);
2✔
1185
}
UNCOV
1186
Value const* Value::findObject(const String& key) const {
×
UNCOV
1187
  return findValue<Value, &Value::isObject>(key);
×
1188
}
1189

1190
Value* Value::demand(char const* begin, char const* end) {
1✔
1191
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
1!
1192
                      "in Json::Value::demand(begin, end): requires "
1193
                      "objectValue or nullValue");
1194
  return &resolveReference(begin, end);
1✔
1195
}
1196
const Value& Value::operator[](const char* key) const {
16,126✔
1197
  Value const* found = find(key, key + strlen(key));
16,126✔
1198
  if (!found)
16,126✔
1199
    return nullSingleton();
1✔
1200
  return *found;
1201
}
1202
Value const& Value::operator[](const String& key) const {
872✔
1203
  Value const* found = find(key);
872✔
1204
  if (!found)
872✔
1205
    return nullSingleton();
3✔
1206
  return *found;
1207
}
1208

1209
Value& Value::operator[](const char* key) {
17,792✔
1210
  return resolveReference(key, key + strlen(key));
17,792✔
1211
}
1212

1213
Value& Value::operator[](const String& key) {
1,864✔
1214
  return resolveReference(key.data(), key.data() + key.length());
1,864✔
1215
}
1216

1217
Value& Value::operator[](const StaticString& key) {
1✔
1218
  return resolveReference(key.c_str());
1✔
1219
}
1220

1221
Value& Value::append(const Value& value) { return append(Value(value)); }
1✔
1222

1223
Value& Value::append(Value&& value) {
53✔
1224
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
53!
1225
                      "in Json::Value::append: requires arrayValue, but found "
1226
                          << valueTypeToString(type()));
1227
  if (type() == nullValue) {
53✔
1228
    *this = Value(arrayValue);
43✔
1229
  }
1230
  return this->value_.map_->emplace(size(), std::move(value)).first->second;
53✔
1231
}
1232

1233
bool Value::insert(ArrayIndex index, const Value& newValue) {
1✔
1234
  return insert(index, Value(newValue));
1✔
1235
}
1236

1237
bool Value::insert(ArrayIndex index, Value&& newValue) {
4✔
1238
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
4!
1239
                      "in Json::Value::insert: requires arrayValue");
1240
  ArrayIndex length = size();
4✔
1241
  if (index > length) {
4✔
1242
    return false;
1243
  }
1244
  for (ArrayIndex i = length; i > index; i--) {
8✔
1245
    (*this)[i] = std::move((*this)[i - 1]);
5✔
1246
  }
1247
  (*this)[index] = std::move(newValue);
3✔
1248
  return true;
3✔
1249
}
1250

1251
Value Value::get(char const* begin, char const* end,
15✔
1252
                 Value const& defaultValue) const {
1253
  Value const* found = find(begin, end);
15✔
1254
  return !found ? defaultValue : *found;
29✔
1255
}
1256
Value Value::get(char const* key, Value const& defaultValue) const {
10✔
1257
  return get(key, key + strlen(key), defaultValue);
10✔
1258
}
1259
Value Value::get(String const& key, Value const& defaultValue) const {
5✔
1260
  return get(key.data(), key.data() + key.length(), defaultValue);
5✔
1261
}
1262

1263
bool Value::removeMember(const char* begin, const char* end, Value* removed) {
9✔
1264
  if (type() != objectValue) {
9!
1265
    return false;
1266
  }
1267
  CZString actualKey(begin, static_cast<unsigned>(end - begin),
9✔
1268
                     CZString::noDuplication);
9✔
1269
  auto it = value_.map_->find(actualKey);
9✔
1270
  if (it == value_.map_->end())
9✔
1271
    return false;
1272
  if (removed)
5✔
1273
    *removed = std::move(it->second);
4✔
1274
  value_.map_->erase(it);
5✔
1275
  return true;
5✔
1276
}
9✔
1277
bool Value::removeMember(const char* key, Value* removed) {
3✔
1278
  return removeMember(key, key + strlen(key), removed);
3✔
1279
}
1280
bool Value::removeMember(String const& key, Value* removed) {
2✔
1281
  return removeMember(key.data(), key.data() + key.length(), removed);
2✔
1282
}
1283

1284
void Value::removeMember(const char* key) {
4✔
1285
  JSON_ASSERT_MESSAGE(
13!
1286
      type() == nullValue || type() == objectValue,
1287
      "in Json::Value::removeMember(): requires objectValue, but found "
1288
          << valueTypeToString(type()));
1289
  if (type() == nullValue)
1!
UNCOV
1290
    return;
×
1291

1292
  CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
1✔
1293
  value_.map_->erase(actualKey);
1✔
1294
}
1✔
1295
void Value::removeMember(const String& key) { removeMember(key.c_str()); }
1✔
1296

1297
bool Value::removeIndex(ArrayIndex index, Value* removed) {
2✔
1298
  if (type() != arrayValue) {
2!
1299
    return false;
1300
  }
1301
  CZString key(index);
2✔
1302
  auto it = value_.map_->find(key);
2✔
1303
  if (it == value_.map_->end()) {
2✔
1304
    return false;
1305
  }
1306
  if (removed)
1!
1307
    *removed = std::move(it->second);
1✔
1308
  ArrayIndex oldSize = size();
1✔
1309
  // shift left all items left, into the place of the "removed"
1310
  for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
1!
UNCOV
1311
    CZString keey(i);
×
UNCOV
1312
    (*value_.map_)[keey] = (*this)[i + 1];
×
UNCOV
1313
  }
×
1314
  // erase the last one ("leftover")
1315
  CZString keyLast(oldSize - 1);
1✔
1316
  auto itLast = value_.map_->find(keyLast);
1✔
1317
  value_.map_->erase(itLast);
1✔
1318
  return true;
1319
}
2✔
1320

1321
bool Value::isMember(char const* begin, char const* end) const {
10✔
1322
  Value const* value = find(begin, end);
10✔
1323
  return nullptr != value;
10✔
1324
}
1325
bool Value::isMember(char const* key) const {
5✔
1326
  return isMember(key, key + strlen(key));
5✔
1327
}
1328
bool Value::isMember(String const& key) const {
5✔
1329
  return isMember(key.data(), key.data() + key.length());
5✔
1330
}
1331

1332
Value::Members Value::getMemberNames() const {
1,130✔
1333
  JSON_ASSERT_MESSAGE(
1,136!
1334
      type() == nullValue || type() == objectValue,
1335
      "in Json::Value::getMemberNames(), value must be objectValue");
1336
  if (type() == nullValue)
1,127!
UNCOV
1337
    return Value::Members();
×
1338
  Members members;
1339
  members.reserve(value_.map_->size());
1,127✔
1340
  ObjectValues::const_iterator it = value_.map_->begin();
1,127✔
1341
  ObjectValues::const_iterator itEnd = value_.map_->end();
1342
  for (; it != itEnd; ++it) {
2,792✔
1343
    members.push_back(String((*it).first.data(), (*it).first.length()));
3,330✔
1344
  }
1345
  return members;
1346
}
1,127✔
1347

1348
static bool IsIntegral(double d) {
1349
  double integral_part;
1350
  return modf(d, &integral_part) == 0.0;
58✔
1351
}
1352

1353
bool Value::isNull() const { return type() == nullValue; }
83✔
1354

1355
bool Value::isBool() const { return type() == booleanValue; }
50✔
1356

1357
bool Value::isInt() const {
104✔
1358
  switch (type()) {
104✔
1359
  case intValue:
34✔
1360
#if defined(JSON_HAS_INT64)
1361
    return value_.int_ >= minInt && value_.int_ <= maxInt;
34✔
1362
#else
1363
    return true;
1364
#endif
1365
  case uintValue:
22✔
1366
    return value_.uint_ <= UInt(maxInt);
22✔
1367
  case realValue:
28✔
1368
    return value_.real_ >= minInt && value_.real_ <= maxInt &&
28✔
1369
           IsIntegral(value_.real_);
1370
  default:
1371
    break;
1372
  }
1373
  return false;
1374
}
1375

1376
bool Value::isUInt() const {
1,659✔
1377
  switch (type()) {
1,659✔
1378
  case intValue:
1,590✔
1379
#if defined(JSON_HAS_INT64)
1380
    return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
1,590✔
1381
#else
1382
    return value_.int_ >= 0;
1383
#endif
1384
  case uintValue:
21✔
1385
#if defined(JSON_HAS_INT64)
1386
    return value_.uint_ <= maxUInt;
21✔
1387
#else
1388
    return true;
1389
#endif
1390
  case realValue:
28✔
1391
    return value_.real_ >= 0 && value_.real_ <= maxUInt &&
28✔
1392
           IsIntegral(value_.real_);
1393
  default:
1394
    break;
1395
  }
1396
  return false;
1397
}
1398

1399
bool Value::isInt64() const {
56✔
1400
#if defined(JSON_HAS_INT64)
1401
  switch (type()) {
56✔
1402
  case intValue:
1403
    return true;
1404
  case uintValue:
13✔
1405
    return value_.uint_ <= UInt64(maxInt64);
13✔
1406
  case realValue:
15✔
1407
    // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
1408
    // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
1409
    // require the value to be strictly less than the limit.
1410
    // minInt64 is -2^63 which can be represented as a double, but since double
1411
    // values in its proximity are also rounded to -2^63, we require the value
1412
    // to be strictly greater than the limit to avoid returning 'true' for
1413
    // values that are not in the range
1414
    return value_.real_ > double(minInt64) && value_.real_ < double(maxInt64) &&
15✔
1415
           IsIntegral(value_.real_);
1416
  default:
1417
    break;
1418
  }
1419
#endif // JSON_HAS_INT64
1420
  return false;
1421
}
1422

1423
bool Value::isUInt64() const {
57✔
1424
#if defined(JSON_HAS_INT64)
1425
  switch (type()) {
57✔
1426
  case intValue:
20✔
1427
    return value_.int_ >= 0;
20✔
1428
  case uintValue:
1429
    return true;
1430
  case realValue:
15✔
1431
    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1432
    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1433
    // require the value to be strictly less than the limit.
1434
    return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
15✔
1435
           IsIntegral(value_.real_);
1436
  default:
1437
    break;
1438
  }
1439
#endif // JSON_HAS_INT64
1440
  return false;
1441
}
1442

1443
bool Value::isIntegral() const {
42✔
1444
  switch (type()) {
42✔
1445
  case intValue:
1446
  case uintValue:
1447
    return true;
1448
  case realValue:
14✔
1449
#if defined(JSON_HAS_INT64)
1450
    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1451
    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1452
    // require the value to be strictly less than the limit.
1453
    // minInt64 is -2^63 which can be represented as a double, but since double
1454
    // values in its proximity are also rounded to -2^63, we require the value
1455
    // to be strictly greater than the limit to avoid returning 'true' for
1456
    // values that are not in the range
1457
    return value_.real_ > double(minInt64) &&
13✔
1458
           value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
26✔
1459
#else
1460
    return value_.real_ >= minInt && value_.real_ <= maxUInt &&
1461
           IsIntegral(value_.real_);
1462
#endif // JSON_HAS_INT64
1463
  default:
1464
    break;
1465
  }
1466
  return false;
1467
}
1468

1469
bool Value::isDouble() const {
169✔
1470
  return type() == intValue || type() == uintValue || type() == realValue;
169✔
1471
}
1472

1473
bool Value::isNumeric() const { return isDouble(); }
119✔
1474

1475
bool Value::isString() const { return type() == stringValue; }
52✔
1476

1477
bool Value::isArray() const { return type() == arrayValue; }
501✔
1478

1479
bool Value::isObject() const { return type() == objectValue; }
432✔
1480

UNCOV
1481
Value::Comments::Comments(const Comments& that)
×
UNCOV
1482
    : ptr_{cloneUnique(that.ptr_)} {}
×
1483

1484
Value::Comments::Comments(Comments&& that) noexcept
125,255✔
1485
    : ptr_{std::move(that.ptr_)} {}
125,255✔
1486

1487
Value::Comments& Value::Comments::operator=(const Comments& that) {
245,217✔
1488
  ptr_ = cloneUnique(that.ptr_);
245,217✔
1489
  return *this;
245,217✔
1490
}
1491

1492
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
489,986!
1493
  ptr_ = std::move(that.ptr_);
1494
  return *this;
489,986✔
1495
}
1496

1497
bool Value::Comments::has(CommentPlacement slot) const {
377,788✔
1498
  return ptr_ && !(*ptr_)[slot].empty();
377,788!
1499
}
1500

1501
String Value::Comments::get(CommentPlacement slot) const {
1,282!
1502
  if (!ptr_)
1,282!
1503
    return {};
1504
  return (*ptr_)[slot];
1,282!
1505
}
1506

1507
void Value::Comments::set(CommentPlacement slot, String comment) {
956✔
1508
  if (slot >= CommentPlacement::numberOfCommentPlacement)
956!
1509
    return;
1510
  if (!ptr_)
956✔
1511
    ptr_ = std::unique_ptr<Array>(new Array());
894✔
1512
  (*ptr_)[slot] = std::move(comment);
1,912!
1513
}
1514

1515
void Value::setComment(String comment, CommentPlacement placement) {
956!
1516
  if (!comment.empty() && (comment.back() == '\n')) {
956!
1517
    // Always discard trailing newline, to aid indentation.
1518
    comment.pop_back();
790✔
1519
  }
1520
  JSON_ASSERT_MESSAGE(
956!
1521
      comment.empty() || comment[0] == '/',
1522
      "in Json::Value::setComment(): Comments must start with /");
1523
  comments_.set(placement, std::move(comment));
956✔
1524
}
956✔
1525

1526
bool Value::hasComment(CommentPlacement placement) const {
377,788✔
1527
  return comments_.has(placement);
377,788✔
1528
}
1529

1530
String Value::getComment(CommentPlacement placement) const {
1,282✔
1531
  return comments_.get(placement);
1,282✔
1532
}
1533

1534
void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
109,627✔
1535

1536
void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
107,834✔
1537

1538
ptrdiff_t Value::getOffsetStart() const { return start_; }
19✔
1539

1540
ptrdiff_t Value::getOffsetLimit() const { return limit_; }
19✔
1541

1542
String Value::toStyledString() const {
5✔
1543
  StreamWriterBuilder builder;
5✔
1544

1545
  String out = this->hasComment(commentBefore) ? "\n" : "";
8✔
1546
  out += Json::writeString(builder, *this);
10✔
1547
  out += '\n';
1548

1549
  return out;
5✔
1550
}
5✔
1551

1552
Value::const_iterator Value::begin() const {
23✔
1553
  switch (type()) {
23✔
1554
  case arrayValue:
10✔
1555
  case objectValue:
1556
    if (value_.map_)
10!
1557
      return const_iterator(value_.map_->begin());
10✔
1558
    break;
1559
  default:
1560
    break;
1561
  }
1562
  return {};
13✔
1563
}
1564

1565
Value::const_iterator Value::end() const {
64✔
1566
  switch (type()) {
64✔
1567
  case arrayValue:
52✔
1568
  case objectValue:
1569
    if (value_.map_)
52!
1570
      return const_iterator(value_.map_->end());
52✔
1571
    break;
1572
  default:
1573
    break;
1574
  }
1575
  return {};
12✔
1576
}
1577

1578
Value::iterator Value::begin() {
39✔
1579
  switch (type()) {
39✔
1580
  case arrayValue:
26✔
1581
  case objectValue:
1582
    if (value_.map_)
26!
1583
      return iterator(value_.map_->begin());
26✔
1584
    break;
1585
  default:
1586
    break;
1587
  }
1588
  return iterator();
13✔
1589
}
1590

1591
Value::iterator Value::end() {
44✔
1592
  switch (type()) {
44✔
1593
  case arrayValue:
29✔
1594
  case objectValue:
1595
    if (value_.map_)
29!
1596
      return iterator(value_.map_->end());
29✔
1597
    break;
1598
  default:
1599
    break;
1600
  }
1601
  return iterator();
15✔
1602
}
1603

1604
// class PathArgument
1605
// //////////////////////////////////////////////////////////////////
1606

1607
PathArgument::PathArgument() = default;
36✔
1608

1609
PathArgument::PathArgument(ArrayIndex index)
4✔
1610
    : index_(index), kind_(kindIndex) {}
4✔
1611

1612
PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {}
2✔
1613

1614
PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {}
10✔
1615

1616
// class Path
1617
// //////////////////////////////////////////////////////////////////
1618

1619
Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
8✔
1620
           const PathArgument& a3, const PathArgument& a4,
1621
           const PathArgument& a5) {
1622
  InArgs in;
1623
  in.reserve(5);
8✔
1624
  in.push_back(&a1);
8✔
1625
  in.push_back(&a2);
8✔
1626
  in.push_back(&a3);
8✔
1627
  in.push_back(&a4);
8✔
1628
  in.push_back(&a5);
8✔
1629
  makePath(path, in);
8✔
1630
}
8✔
1631

1632
void Path::makePath(const String& path, const InArgs& in) {
8✔
1633
  const char* current = path.c_str();
1634
  const char* end = current + path.length();
8✔
1635
  auto itInArg = in.begin();
8✔
1636
  while (current != end) {
42✔
1637
    if (*current == '[') {
34✔
1638
      ++current;
4✔
1639
      if (*current == '%')
4✔
1640
        addPathInArg(path, in, itInArg, PathArgument::kindIndex);
2✔
1641
      else {
1642
        ArrayIndex index = 0;
1643
        for (; current != end && *current >= '0' && *current <= '9'; ++current)
4!
1644
          index = index * 10 + ArrayIndex(*current - '0');
2✔
1645
        args_.push_back(index);
4✔
1646
      }
1647
      if (current == end || *++current != ']')
4!
1648
        invalidPath(path, int(current - path.c_str()));
2✔
1649
    } else if (*current == '%') {
30✔
1650
      addPathInArg(path, in, itInArg, PathArgument::kindKey);
2✔
1651
      ++current;
2✔
1652
    } else if (*current == '.' || *current == ']') {
28✔
1653
      ++current;
18✔
1654
    } else {
1655
      const char* beginName = current;
1656
      while (current != end && !strchr("[.", *current))
88✔
1657
        ++current;
78✔
1658
      args_.push_back(String(beginName, current));
20✔
1659
    }
1660
  }
1661
}
8✔
1662

1663
void Path::addPathInArg(const String& /*path*/, const InArgs& in,
4!
1664
                        InArgs::const_iterator& itInArg,
1665
                        PathArgument::Kind kind) {
1666
  if (itInArg == in.end()) {
4!
1667
    // Error: missing argument %d
1668
  } else if ((*itInArg)->kind_ != kind) {
4!
1669
    // Error: bad argument type
1670
  } else {
1671
    args_.push_back(**itInArg++);
4✔
1672
  }
1673
}
4✔
1674

1675
void Path::invalidPath(const String& /*path*/, int /*location*/) {
2✔
1676
  // Error: invalid path.
1677
}
2✔
1678

1679
const Value& Path::resolve(const Value& root) const {
6✔
1680
  const Value* node = &root;
1681
  for (const auto& arg : args_) {
14✔
1682
    if (arg.kind_ == PathArgument::kindIndex) {
12✔
1683
      if (!node->isArray() || !node->isValidIndex(arg.index_)) {
2!
1684
        // Error: unable to resolve path (array value expected at position... )
1685
        return Value::nullSingleton();
1✔
1686
      }
1687
      node = &((*node)[arg.index_]);
1✔
1688
    } else if (arg.kind_ == PathArgument::kindKey) {
10!
1689
      if (!node->isObject()) {
10✔
1690
        // Error: unable to resolve path (object value expected at position...)
1691
        return Value::nullSingleton();
1✔
1692
      }
1693
      node = &((*node)[arg.key_]);
9✔
1694
      if (node == &Value::nullSingleton()) {
9✔
1695
        // Error: unable to resolve path (object has no member named '' at
1696
        // position...)
1697
        return Value::nullSingleton();
2✔
1698
      }
1699
    }
1700
  }
1701
  return *node;
1702
}
1703

1704
Value Path::resolve(const Value& root, const Value& defaultValue) const {
6✔
1705
  const Value* node = &root;
1706
  for (const auto& arg : args_) {
14✔
1707
    if (arg.kind_ == PathArgument::kindIndex) {
12✔
1708
      if (!node->isArray() || !node->isValidIndex(arg.index_))
3✔
1709
        return defaultValue;
2✔
1710
      node = &((*node)[arg.index_]);
1✔
1711
    } else if (arg.kind_ == PathArgument::kindKey) {
9!
1712
      if (!node->isObject())
9✔
1713
        return defaultValue;
1✔
1714
      node = &((*node)[arg.key_]);
8✔
1715
      if (node == &Value::nullSingleton())
8✔
1716
        return defaultValue;
1✔
1717
    }
1718
  }
1719
  return *node;
2✔
1720
}
1721

1722
Value& Path::make(Value& root) const {
2✔
1723
  Value* node = &root;
1724
  for (const auto& arg : args_) {
6✔
1725
    if (arg.kind_ == PathArgument::kindIndex) {
4✔
1726
      if (!node->isArray()) {
1✔
1727
        // Error: node is not an array at position ...
1728
      }
1729
      node = &((*node)[arg.index_]);
1✔
1730
    } else if (arg.kind_ == PathArgument::kindKey) {
3!
1731
      if (!node->isObject()) {
3✔
1732
        // Error: node is not an object at position...
1733
      }
1734
      node = &((*node)[arg.key_]);
3✔
1735
    }
1736
  }
1737
  return *node;
2✔
1738
}
1739

1740
const char* version() { return JSONCPP_VERSION_STRING; }
1✔
1741

1742
} // namespace Json
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc