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

open-source-parsers / jsoncpp / 22606685123

03 Mar 2026 03:16AM UTC coverage: 89.464% (-0.5%) from 89.937%
22606685123

Pull #1654

github

baylesj
Fix MSAN issue in #1626

This patch fixes an MSAN issue by changing CZString
initialization.
Pull Request #1654: Fix MSAN issue in #1626

2160 of 2575 branches covered (83.88%)

Branch coverage included in aggregate %.

8 of 17 new or added lines in 1 file covered. (47.06%)

8 existing lines in 1 file now uncovered.

2544 of 2683 relevant lines covered (94.82%)

24080.81 hits per line

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

86.82
/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
#ifdef JSONCPP_HAS_STRING_VIEW
21
#include <string_view>
22
#endif
23

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

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

47
// Disable warning C4702 : unreachable code
48
#if defined(_MSC_VER)
49
#pragma warning(disable : 4702)
50
#endif
51

52
#define JSON_ASSERT_UNREACHABLE assert(false)
53

54
namespace Json {
55
template <typename T>
56
static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
253,265✔
57
  std::unique_ptr<T> r;
253,265✔
58
  if (p) {
253,265✔
59
    r = std::unique_ptr<T>(new T(*p));
6✔
60
  }
61
  return r;
253,265✔
62
}
63

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

73
// static
74
Value const& Value::nullSingleton() {
127,473✔
75
  static Value const nullStatic;
127,473!
76
  return nullStatic;
127,473✔
77
}
78

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

85
// static
86
Value const& Value::nullRef = Value::nullSingleton();
87
#endif
88

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

103
template <typename T> static inline double integerToDouble(T value) {
104
  return static_cast<double>(value);
105
}
106

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

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

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

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

192
} // namespace Json
193

194
// //////////////////////////////////////////////////////////////////
195
// //////////////////////////////////////////////////////////////////
196
// //////////////////////////////////////////////////////////////////
197
// ValueInternals...
198
// //////////////////////////////////////////////////////////////////
199
// //////////////////////////////////////////////////////////////////
200
// //////////////////////////////////////////////////////////////////
201
#if !defined(JSON_IS_AMALGAMATION)
202

203
#include "json_valueiterator.inl"
204
#endif // if !defined(JSON_IS_AMALGAMATION)
205

206
namespace Json {
207

208
#if JSON_USE_EXCEPTION
209
Exception::Exception(String msg) : msg_(std::move(msg)) {}
48✔
210
Exception::~Exception() noexcept = default;
48✔
211
char const* Exception::what() const noexcept { return msg_.c_str(); }
6✔
212
RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
16✔
213
LogicError::LogicError(String const& msg) : Exception(msg) {}
80✔
214
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
8✔
215
  throw RuntimeError(msg);
8✔
216
}
217
JSONCPP_NORETURN void throwLogicError(String const& msg) {
40✔
218
  throw LogicError(msg);
40✔
219
}
220
#else // !JSON_USE_EXCEPTION
221
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
222
  std::cerr << msg << std::endl;
223
  abort();
224
}
225
JSONCPP_NORETURN void throwLogicError(String const& msg) {
226
  std::cerr << msg << std::endl;
227
  abort();
228
}
229
#endif
230

231
// //////////////////////////////////////////////////////////////////
232
// //////////////////////////////////////////////////////////////////
233
// //////////////////////////////////////////////////////////////////
234
// class Value::CZString
235
// //////////////////////////////////////////////////////////////////
236
// //////////////////////////////////////////////////////////////////
237
// //////////////////////////////////////////////////////////////////
238

239
// Notes: policy_ indicates if the string was allocated when
240
// a string is stored.
241

242
Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}
269,527✔
243

244
Value::CZString::CZString(char const* str, unsigned length,
36,406✔
245
                          DuplicationPolicy allocate)
36,406✔
246
    : cstr_(str) {
36,406✔
247
  // allocate != duplicate
248
  storage_.policy_ = allocate & 0x3;
36,406✔
249
  storage_.length_ = length & 0x3FFFFFFF;
36,406✔
250
}
36,406✔
251

252
Value::CZString::CZString(const CZString& other) {
252,970✔
253
  cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
187,751✔
254
               ? duplicateStringValue(other.cstr_, other.storage_.length_)
440,721✔
255
               : other.cstr_);
256
  if (other.cstr_) {
252,970✔
257
    storage_.policy_ =
30,274✔
258
        static_cast<unsigned>(
259
            other.cstr_
260
                ? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
30,274✔
261
                           noDuplication
262
                       ? noDuplication
30,274✔
263
                       : duplicate)
264
                : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
30,274✔
265
        3U;
266
    storage_.length_ = other.storage_.length_;
30,274✔
267
  } else {
268
    index_ = other.index_;
222,696✔
269
  }
270
}
252,970✔
271

NEW
272
Value::CZString::CZString(CZString&& other) noexcept : cstr_(other.cstr_) {
×
NEW
273
  if (other.cstr_) {
×
NEW
274
    storage_.policy_ = other.storage_.policy_;
×
NEW
275
    storage_.length_ = other.storage_.length_;
×
276
  } else {
NEW
277
    index_ = other.index_;
×
278
  }
279
  other.cstr_ = nullptr;
×
280
}
×
281

282
Value::CZString::~CZString() {
558,903✔
283
  if (cstr_ && storage_.policy_ == duplicate) {
558,903✔
284
    releaseStringValue(const_cast<char*>(cstr_),
285
                       storage_.length_ + 1U); // +1 for null terminating
286
                                               // character for sake of
287
                                               // completeness but not actually
288
                                               // necessary
289
  }
290
}
558,903✔
291

292
void Value::CZString::swap(CZString& other) {
×
293
  std::swap(cstr_, other.cstr_);
294
  std::swap(index_, other.index_);
295
}
×
296

297
Value::CZString& Value::CZString::operator=(const CZString& other) {
×
298
  cstr_ = other.cstr_;
×
299
  index_ = other.index_;
×
300
  return *this;
×
301
}
302

303
Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
×
304
  cstr_ = other.cstr_;
×
NEW
305
  if (other.cstr_) {
×
NEW
306
    storage_.policy_ = other.storage_.policy_;
×
NEW
307
    storage_.length_ = other.storage_.length_;
×
308
  } else {
NEW
309
    index_ = other.index_;
×
310
  }
311
  other.cstr_ = nullptr;
×
312
  return *this;
×
313
}
314

315
bool Value::CZString::operator<(const CZString& other) const {
3,940,902✔
316
  if (!cstr_)
3,940,902✔
317
    return index_ < other.index_;
3,782,636✔
318
  // return strcmp(cstr_, other.cstr_) < 0;
319
  // Assume both are strings.
320
  unsigned this_len = this->storage_.length_;
158,266✔
321
  unsigned other_len = other.storage_.length_;
158,266✔
322
  unsigned min_len = std::min<unsigned>(this_len, other_len);
158,266✔
323
  JSON_ASSERT(this->cstr_ && other.cstr_);
158,266!
324
  int comp = memcmp(this->cstr_, other.cstr_, min_len);
158,266✔
325
  if (comp < 0)
158,266✔
326
    return true;
327
  if (comp > 0)
80,771✔
328
    return false;
329
  return (this_len < other_len);
40,411✔
330
}
331

332
bool Value::CZString::operator==(const CZString& other) const {
120,275✔
333
  if (!cstr_)
120,275✔
334
    return index_ == other.index_;
104,928✔
335
  // return strcmp(cstr_, other.cstr_) == 0;
336
  // Assume both are strings.
337
  unsigned this_len = this->storage_.length_;
15,347✔
338
  unsigned other_len = other.storage_.length_;
15,347✔
339
  if (this_len != other_len)
15,347✔
340
    return false;
341
  JSON_ASSERT(this->cstr_ && other.cstr_);
5,380!
342
  int comp = memcmp(this->cstr_, other.cstr_, this_len);
5,380✔
343
  return comp == 0;
5,380✔
344
}
345

346
ArrayIndex Value::CZString::index() const { return index_; }
717✔
347

348
// const char* Value::CZString::c_str() const { return cstr_; }
349
const char* Value::CZString::data() const { return cstr_; }
1,727✔
350
unsigned Value::CZString::length() const { return storage_.length_; }
1,711✔
351
bool Value::CZString::isStaticString() const {
3✔
352
  return storage_.policy_ == noDuplication;
3✔
353
}
354

355
// //////////////////////////////////////////////////////////////////
356
// //////////////////////////////////////////////////////////////////
357
// //////////////////////////////////////////////////////////////////
358
// class Value::Value
359
// //////////////////////////////////////////////////////////////////
360
// //////////////////////////////////////////////////////////////////
361
// //////////////////////////////////////////////////////////////////
362

363
/*! \internal Default constructor initialization must be equivalent to:
364
 * memset( this, 0, sizeof(Value) )
365
 * This optimization is used in ValueInternalMap fast allocator.
366
 */
367
Value::Value(ValueType type) {
118,714✔
368
  static char const emptyString[] = "";
369
  initBasic(type);
118,714✔
370
  switch (type) {
118,714!
371
  case nullValue:
372
    break;
373
  case intValue:
2✔
374
  case uintValue:
375
    value_.int_ = 0;
2✔
376
    break;
2✔
377
  case realValue:
1✔
378
    value_.real_ = 0.0;
1✔
379
    break;
1✔
380
  case stringValue:
×
381
    // allocated_ == false, so this is safe.
382
    value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
×
383
    break;
×
384
  case arrayValue:
9,118✔
385
  case objectValue:
386
    value_.map_ = new ObjectValues();
9,118✔
387
    break;
9,118✔
388
  case booleanValue:
×
389
    value_.bool_ = false;
×
390
    break;
×
391
  default:
×
392
    JSON_ASSERT_UNREACHABLE;
×
393
  }
394
}
118,714✔
395

396
Value::Value(Int value) {
1,486✔
397
  initBasic(intValue);
1,486✔
398
  value_.int_ = value;
1,486✔
399
}
1,486✔
400

401
Value::Value(UInt value) {
212✔
402
  initBasic(uintValue);
212✔
403
  value_.uint_ = value;
212✔
404
}
212✔
405
#if defined(JSON_HAS_INT64)
406
Value::Value(Int64 value) {
105,102✔
407
  initBasic(intValue);
105,102✔
408
  value_.int_ = value;
105,102✔
409
}
105,102✔
410
Value::Value(UInt64 value) {
124✔
411
  initBasic(uintValue);
124✔
412
  value_.uint_ = value;
124✔
413
}
124✔
414
#endif // defined(JSON_HAS_INT64)
415

416
Value::Value(double value) {
577✔
417
  initBasic(realValue);
577✔
418
  value_.real_ = value;
577✔
419
}
577✔
420

421
Value::Value(const char* value) {
1,233✔
422
  initBasic(stringValue, true);
1,233✔
423
  JSON_ASSERT_MESSAGE(value != nullptr,
1,233!
424
                      "Null Value Passed to Value Constructor");
425
  value_.string_ = duplicateAndPrefixStringValue(
2,466✔
426
      value, static_cast<unsigned>(strlen(value)));
1,233✔
427
}
1,233✔
428

429
Value::Value(const char* begin, const char* end) {
2✔
430
  initBasic(stringValue, true);
2✔
431
  value_.string_ =
2✔
432
      duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
2✔
433
}
2✔
434

435
Value::Value(const String& value) {
1,259✔
436
  initBasic(stringValue, true);
1,259✔
437
  value_.string_ = duplicateAndPrefixStringValue(
1,259✔
438
      value.data(), static_cast<unsigned>(value.length()));
439
}
1,259✔
440

441
#ifdef JSONCPP_HAS_STRING_VIEW
442
Value::Value(std::string_view value) {
443
  initBasic(stringValue, true);
444
  value_.string_ = duplicateAndPrefixStringValue(
445
      value.data(), static_cast<unsigned>(value.length()));
446
}
447
#endif
448

449
Value::Value(const StaticString& value) {
2✔
450
  initBasic(stringValue);
2✔
451
  value_.string_ = const_cast<char*>(value.c_str());
2✔
452
}
2✔
453

454
Value::Value(bool value) {
14,600✔
455
  initBasic(booleanValue);
14,600✔
456
  value_.bool_ = value;
14,600✔
457
}
14,600✔
458

459
Value::Value(const Value& other) {
253,257✔
460
  dupPayload(other);
253,257✔
461
  dupMeta(other);
253,257✔
462
}
253,257✔
463

464
Value::Value(Value&& other) noexcept {
50✔
465
  initBasic(nullValue);
50✔
466
  swap(other);
50✔
467
}
50✔
468

469
Value::~Value() {
496,618✔
470
  releasePayload();
496,618✔
471
  value_.uint_ = 0;
496,618✔
472
}
496,618✔
473

474
Value& Value::operator=(const Value& other) {
18✔
475
  Value(other).swap(*this);
18✔
476
  return *this;
18✔
477
}
478

479
Value& Value::operator=(Value&& other) noexcept {
124,959✔
480
  other.swap(*this);
124,959✔
481
  return *this;
124,959✔
482
}
483

484
void Value::swapPayload(Value& other) {
238,804✔
485
  std::swap(bits_, other.bits_);
486
  std::swap(value_, other.value_);
487
}
238,804✔
488

489
void Value::copyPayload(const Value& other) {
8✔
490
  releasePayload();
8✔
491
  dupPayload(other);
8✔
492
}
8✔
493

494
void Value::swap(Value& other) {
125,028✔
495
  swapPayload(other);
125,028✔
496
  std::swap(comments_, other.comments_);
125,028✔
497
  std::swap(start_, other.start_);
498
  std::swap(limit_, other.limit_);
499
}
125,028✔
500

501
void Value::copy(const Value& other) {
8✔
502
  copyPayload(other);
8✔
503
  dupMeta(other);
8✔
504
}
8✔
505

506
ValueType Value::type() const {
2,269,811✔
507
  return static_cast<ValueType>(bits_.value_type_);
2,269,811✔
508
}
509

510
int Value::compare(const Value& other) const {
120✔
511
  if (*this < other)
120✔
512
    return -1;
513
  if (*this > other)
89✔
514
    return 1;
31✔
515
  return 0;
516
}
517

518
bool Value::operator<(const Value& other) const {
1,279✔
519
  int typeDelta = type() - other.type();
1,279✔
520
  if (typeDelta)
1,279✔
521
    return typeDelta < 0;
77✔
522
  switch (type()) {
1,202!
523
  case nullValue:
524
    return false;
525
  case intValue:
564✔
526
    return value_.int_ < other.value_.int_;
564✔
527
  case uintValue:
34✔
528
    return value_.uint_ < other.value_.uint_;
34✔
529
  case realValue:
46✔
530
    return value_.real_ < other.value_.real_;
46✔
531
  case booleanValue:
35✔
532
    return value_.bool_ < other.value_.bool_;
35✔
533
  case stringValue: {
175✔
534
    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
175!
535
      return other.value_.string_ != nullptr;
×
536
    }
537
    unsigned this_len;
538
    unsigned other_len;
539
    char const* this_str;
540
    char const* other_str;
541
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
542
                         &this_str);
543
    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
544
                         &other_str);
545
    unsigned min_len = std::min<unsigned>(this_len, other_len);
175✔
546
    JSON_ASSERT(this_str && other_str);
547
    int comp = memcmp(this_str, other_str, min_len);
175✔
548
    if (comp < 0)
175✔
549
      return true;
550
    if (comp > 0)
163✔
551
      return false;
552
    return (this_len < other_len);
153✔
553
  }
554
  case arrayValue:
312✔
555
  case objectValue: {
556
    auto thisSize = value_.map_->size();
312✔
557
    auto otherSize = other.value_.map_->size();
312✔
558
    if (thisSize != otherSize)
312✔
559
      return thisSize < otherSize;
66✔
560
    return (*value_.map_) < (*other.value_.map_);
246✔
561
  }
562
  default:
×
563
    JSON_ASSERT_UNREACHABLE;
×
564
  }
565
  return false; // unreachable
566
}
567

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

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

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

574
bool Value::operator==(const Value& other) const {
313✔
575
  if (type() != other.type())
313✔
576
    return false;
577
  switch (type()) {
298!
578
  case nullValue:
579
    return true;
580
  case intValue:
79✔
581
    return value_.int_ == other.value_.int_;
79✔
582
  case uintValue:
10✔
583
    return value_.uint_ == other.value_.uint_;
10✔
584
  case realValue:
14✔
585
    return value_.real_ == other.value_.real_;
14✔
586
  case booleanValue:
15✔
587
    return value_.bool_ == other.value_.bool_;
15✔
588
  case stringValue: {
87✔
589
    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
87!
590
      return (value_.string_ == other.value_.string_);
×
591
    }
592
    unsigned this_len;
593
    unsigned other_len;
594
    char const* this_str;
595
    char const* other_str;
596
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
597
                         &this_str);
598
    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
599
                         &other_str);
600
    if (this_len != other_len)
87✔
601
      return false;
602
    JSON_ASSERT(this_str && other_str);
603
    int comp = memcmp(this_str, other_str, this_len);
80✔
604
    return comp == 0;
80✔
605
  }
606
  case arrayValue:
60✔
607
  case objectValue:
608
    return value_.map_->size() == other.value_.map_->size() &&
107✔
609
           (*value_.map_) == (*other.value_.map_);
610
  default:
×
611
    JSON_ASSERT_UNREACHABLE;
×
612
  }
613
  return false; // unreachable
614
}
615

616
bool Value::operator!=(const Value& other) const { return !(*this == other); }
131✔
617

618
const char* Value::asCString() const {
4✔
619
  JSON_ASSERT_MESSAGE(type() == stringValue,
6✔
620
                      "in Json::Value::asCString(): requires stringValue");
621
  if (value_.string_ == nullptr)
3!
622
    return nullptr;
623
  unsigned this_len;
624
  char const* this_str;
625
  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
626
                       &this_str);
627
  return this_str;
628
}
629

630
#if JSONCPP_USE_SECURE_MEMORY
631
unsigned Value::getCStringLength() const {
632
  JSON_ASSERT_MESSAGE(type() == stringValue,
633
                      "in Json::Value::asCString(): requires stringValue");
634
  if (value_.string_ == 0)
635
    return 0;
636
  unsigned this_len;
637
  char const* this_str;
638
  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
639
                       &this_str);
640
  return this_len;
641
}
642
#endif
643

644
bool Value::getString(char const** begin, char const** end) const {
782✔
645
  if (type() != stringValue)
782!
646
    return false;
647
  if (value_.string_ == nullptr)
782!
648
    return false;
649
  unsigned length;
650
  decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
651
                       begin);
652
  *end = *begin + length;
782✔
653
  return true;
782✔
654
}
655

656
#ifdef JSONCPP_HAS_STRING_VIEW
657
bool Value::getString(std::string_view* str) const {
658
  if (type() != stringValue)
659
    return false;
660
  if (value_.string_ == nullptr)
661
    return false;
662
  const char* begin;
663
  unsigned length;
664
  decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
665
                       &begin);
666
  *str = std::string_view(begin, length);
667
  return true;
668
}
669
#endif
670

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

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

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

741
#if defined(JSON_HAS_INT64)
742

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

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

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

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

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

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

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

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

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

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

936
Value::operator bool() const { return !isNull(); }
4✔
937

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

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

973
Value& Value::operator[](ArrayIndex index) {
216,243✔
974
  JSON_ASSERT_MESSAGE(
216,249✔
975
      type() == nullValue || type() == arrayValue,
976
      "in Json::Value::operator[](ArrayIndex): requires arrayValue");
977
  if (type() == nullValue)
216,240✔
978
    *this = Value(arrayValue);
16✔
979
  CZString key(index);
216,240✔
980
  auto it = value_.map_->lower_bound(key);
216,240✔
981
  if (it != value_.map_->end() && (*it).first == key)
216,240✔
982
    return (*it).second;
104,903✔
983

984
  ObjectValues::value_type defaultValue(key, nullSingleton());
111,337✔
985
  it = value_.map_->insert(it, defaultValue);
111,337✔
986
  return (*it).second;
111,337✔
987
}
216,240✔
988

989
Value& Value::operator[](int index) {
111,235✔
990
  JSON_ASSERT_MESSAGE(
111,235!
991
      index >= 0,
992
      "in Json::Value::operator[](int index): index cannot be negative");
993
  return (*this)[ArrayIndex(index)];
111,235✔
994
}
995

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

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

1016
void Value::initBasic(ValueType type, bool allocated) {
243,361✔
1017
  setType(type);
1018
  setIsAllocated(allocated);
1019
  comments_ = Comments{};
243,361✔
1020
  start_ = 0;
243,361✔
1021
  limit_ = 0;
243,361✔
1022
}
243,361✔
1023

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

1056
void Value::releasePayload() {
496,626✔
1057
  switch (type()) {
496,626!
1058
  case nullValue:
1059
  case intValue:
1060
  case uintValue:
1061
  case realValue:
1062
  case booleanValue:
1063
    break;
1064
  case stringValue:
1065
    if (isAllocated())
2,625✔
1066
      releasePrefixedStringValue(value_.string_);
2,623✔
1067
    break;
1068
  case arrayValue:
9,172✔
1069
  case objectValue:
1070
    delete value_.map_;
18,344!
1071
    break;
1072
  default:
×
1073
    JSON_ASSERT_UNREACHABLE;
×
1074
  }
1075
}
496,626✔
1076

1077
void Value::dupMeta(const Value& other) {
253,265✔
1078
  comments_ = other.comments_;
253,265✔
1079
  start_ = other.start_;
253,265✔
1080
  limit_ = other.limit_;
253,265✔
1081
}
253,265✔
1082

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

1098
  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
1✔
1099
  it = value_.map_->insert(it, defaultValue);
1✔
1100
  Value& value = (*it).second;
1✔
1101
  return value;
1102
}
1✔
1103

1104
// @param key is not null-terminated.
1105
Value& Value::resolveReference(char const* key, char const* end) {
19,464✔
1106
  JSON_ASSERT_MESSAGE(
19,470✔
1107
      type() == nullValue || type() == objectValue,
1108
      "in Json::Value::resolveReference(key, end): requires objectValue");
1109
  if (type() == nullValue)
19,461✔
1110
    *this = Value(objectValue);
1,680✔
1111
  CZString actualKey(key, static_cast<unsigned>(end - key),
19,461✔
1112
                     CZString::duplicateOnCopy);
19,461✔
1113
  auto it = value_.map_->lower_bound(actualKey);
19,461✔
1114
  if (it != value_.map_->end() && (*it).first == actualKey)
19,461✔
1115
    return (*it).second;
4,345✔
1116

1117
  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
15,116✔
1118
  it = value_.map_->insert(it, defaultValue);
15,116✔
1119
  Value& value = (*it).second;
15,116✔
1120
  return value;
1121
}
19,461✔
1122

1123
Value Value::get(ArrayIndex index, const Value& defaultValue) const {
6✔
1124
  const Value* value = &((*this)[index]);
6✔
1125
  return value == &nullSingleton() ? defaultValue : *value;
11✔
1126
}
1127

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

1130
Value const* Value::find(char const* begin, char const* end) const {
16,934✔
1131
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
16,934!
1132
                      "in Json::Value::find(begin, end): requires "
1133
                      "objectValue or nullValue");
1134
  if (type() == nullValue)
16,934!
1135
    return nullptr;
1136
  CZString actualKey(begin, static_cast<unsigned>(end - begin),
16,934✔
1137
                     CZString::noDuplication);
16,934✔
1138
  ObjectValues::const_iterator it = value_.map_->find(actualKey);
16,934✔
1139
  if (it == value_.map_->end())
16,934✔
1140
    return nullptr;
1141
  return &(*it).second;
16,919✔
1142
}
16,934✔
1143
Value const* Value::find(const String& key) const {
896✔
1144
  return find(key.data(), key.data() + key.length());
896✔
1145
}
1146

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

1184
Value* Value::demand(char const* begin, char const* end) {
1✔
1185
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
1!
1186
                      "in Json::Value::demand(begin, end): requires "
1187
                      "objectValue or nullValue");
1188
  return &resolveReference(begin, end);
1✔
1189
}
1190
#ifdef JSONCPP_HAS_STRING_VIEW
1191
const Value& Value::operator[](std::string_view key) const {
1192
  Value const* found = find(key.data(), key.data() + key.length());
1193
  if (!found)
1194
    return nullSingleton();
1195
  return *found;
1196
}
1197
Value& Value::operator[](std::string_view key) {
1198
  return resolveReference(key.data(), key.data() + key.length());
1199
}
1200
#else
1201
const Value& Value::operator[](const char* key) const {
16,010✔
1202
  Value const* found = find(key, key + strlen(key));
16,010✔
1203
  if (!found)
16,010✔
1204
    return nullSingleton();
1✔
1205
  return *found;
1206
}
1207
Value const& Value::operator[](const String& key) const {
872✔
1208
  Value const* found = find(key);
872✔
1209
  if (!found)
872✔
1210
    return nullSingleton();
3✔
1211
  return *found;
1212
}
1213

1214
Value& Value::operator[](const char* key) {
17,599✔
1215
  return resolveReference(key, key + strlen(key));
17,599✔
1216
}
1217

1218
Value& Value::operator[](const String& key) {
1,864✔
1219
  return resolveReference(key.data(), key.data() + key.length());
1,864✔
1220
}
1221
#endif
1222

1223
Value& Value::operator[](const StaticString& key) {
1✔
1224
  return resolveReference(key.c_str());
1✔
1225
}
1226

1227
Value& Value::append(const Value& value) { return append(Value(value)); }
1✔
1228

1229
Value& Value::append(Value&& value) {
49✔
1230
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
49!
1231
                      "in Json::Value::append: requires arrayValue");
1232
  if (type() == nullValue) {
49✔
1233
    *this = Value(arrayValue);
40✔
1234
  }
1235
  return this->value_.map_->emplace(size(), std::move(value)).first->second;
49✔
1236
}
1237

1238
bool Value::insert(ArrayIndex index, const Value& newValue) {
1✔
1239
  return insert(index, Value(newValue));
1✔
1240
}
1241

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

1256
Value Value::get(char const* begin, char const* end,
15✔
1257
                 Value const& defaultValue) const {
1258
  Value const* found = find(begin, end);
15✔
1259
  return !found ? defaultValue : *found;
29✔
1260
}
1261
#ifdef JSONCPP_HAS_STRING_VIEW
1262
Value Value::get(std::string_view key, const Value& defaultValue) const {
1263
  return get(key.data(), key.data() + key.length(), defaultValue);
1264
}
1265
#else
1266
Value Value::get(char const* key, Value const& defaultValue) const {
10✔
1267
  return get(key, key + strlen(key), defaultValue);
10✔
1268
}
1269
Value Value::get(String const& key, Value const& defaultValue) const {
5✔
1270
  return get(key.data(), key.data() + key.length(), defaultValue);
5✔
1271
}
1272
#endif
1273

1274
bool Value::removeMember(const char* begin, const char* end, Value* removed) {
9✔
1275
  if (type() != objectValue) {
9!
1276
    return false;
1277
  }
1278
  CZString actualKey(begin, static_cast<unsigned>(end - begin),
9✔
1279
                     CZString::noDuplication);
9✔
1280
  auto it = value_.map_->find(actualKey);
9✔
1281
  if (it == value_.map_->end())
9✔
1282
    return false;
1283
  if (removed)
5✔
1284
    *removed = std::move(it->second);
4✔
1285
  value_.map_->erase(it);
5✔
1286
  return true;
5✔
1287
}
9✔
1288
#ifdef JSONCPP_HAS_STRING_VIEW
1289
bool Value::removeMember(std::string_view key, Value* removed) {
1290
  return removeMember(key.data(), key.data() + key.length(), removed);
1291
}
1292
#else
1293
bool Value::removeMember(const char* key, Value* removed) {
3✔
1294
  return removeMember(key, key + strlen(key), removed);
3✔
1295
}
1296
bool Value::removeMember(String const& key, Value* removed) {
2✔
1297
  return removeMember(key.data(), key.data() + key.length(), removed);
2✔
1298
}
1299
#endif
1300

1301
#ifdef JSONCPP_HAS_STRING_VIEW
1302
void Value::removeMember(std::string_view key) {
1303
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
1304
                      "in Json::Value::removeMember(): requires objectValue");
1305
  if (type() == nullValue)
1306
    return;
1307

1308
  CZString actualKey(key.data(), unsigned(key.length()),
1309
                     CZString::noDuplication);
1310
  value_.map_->erase(actualKey);
1311
}
1312
#else
1313
void Value::removeMember(const char* key) {
4✔
1314
  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
10!
1315
                      "in Json::Value::removeMember(): requires objectValue");
1316
  if (type() == nullValue)
1!
1317
    return;
×
1318

1319
  CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
1✔
1320
  value_.map_->erase(actualKey);
1✔
1321
}
1✔
1322
void Value::removeMember(const String& key) { removeMember(key.c_str()); }
1✔
1323
#endif
1324

1325
bool Value::removeIndex(ArrayIndex index, Value* removed) {
2✔
1326
  if (type() != arrayValue) {
2!
1327
    return false;
1328
  }
1329
  CZString key(index);
2✔
1330
  auto it = value_.map_->find(key);
2✔
1331
  if (it == value_.map_->end()) {
2✔
1332
    return false;
1333
  }
1334
  if (removed)
1!
1335
    *removed = std::move(it->second);
1✔
1336
  ArrayIndex oldSize = size();
1✔
1337
  // shift left all items left, into the place of the "removed"
1338
  for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
1!
1339
    CZString keey(i);
×
1340
    (*value_.map_)[keey] = (*this)[i + 1];
×
1341
  }
×
1342
  // erase the last one ("leftover")
1343
  CZString keyLast(oldSize - 1);
1✔
1344
  auto itLast = value_.map_->find(keyLast);
1✔
1345
  value_.map_->erase(itLast);
1✔
1346
  return true;
1347
}
2✔
1348

1349
bool Value::isMember(char const* begin, char const* end) const {
10✔
1350
  Value const* value = find(begin, end);
10✔
1351
  return nullptr != value;
10✔
1352
}
1353
#ifdef JSONCPP_HAS_STRING_VIEW
1354
bool Value::isMember(std::string_view key) const {
1355
  return isMember(key.data(), key.data() + key.length());
1356
}
1357
#else
1358
bool Value::isMember(char const* key) const {
5✔
1359
  return isMember(key, key + strlen(key));
5✔
1360
}
1361
bool Value::isMember(String const& key) const {
5✔
1362
  return isMember(key.data(), key.data() + key.length());
5✔
1363
}
1364
#endif
1365

1366
Value::Members Value::getMemberNames() const {
1,130✔
1367
  JSON_ASSERT_MESSAGE(
1,136!
1368
      type() == nullValue || type() == objectValue,
1369
      "in Json::Value::getMemberNames(), value must be objectValue");
1370
  if (type() == nullValue)
1,127!
1371
    return Value::Members();
×
1372
  Members members;
1373
  members.reserve(value_.map_->size());
1,127✔
1374
  ObjectValues::const_iterator it = value_.map_->begin();
1,127✔
1375
  ObjectValues::const_iterator itEnd = value_.map_->end();
1376
  for (; it != itEnd; ++it) {
2,792✔
1377
    members.push_back(String((*it).first.data(), (*it).first.length()));
3,330✔
1378
  }
1379
  return members;
1380
}
1,127✔
1381

1382
static bool IsIntegral(double d) {
1383
  double integral_part;
1384
  return modf(d, &integral_part) == 0.0;
58✔
1385
}
1386

1387
bool Value::isNull() const { return type() == nullValue; }
82✔
1388

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

1391
bool Value::isInt() const {
102✔
1392
  switch (type()) {
102✔
1393
  case intValue:
32✔
1394
#if defined(JSON_HAS_INT64)
1395
    return value_.int_ >= minInt && value_.int_ <= maxInt;
32✔
1396
#else
1397
    return true;
1398
#endif
1399
  case uintValue:
22✔
1400
    return value_.uint_ <= UInt(maxInt);
22✔
1401
  case realValue:
28✔
1402
    return value_.real_ >= minInt && value_.real_ <= maxInt &&
28✔
1403
           IsIntegral(value_.real_);
1404
  default:
1405
    break;
1406
  }
1407
  return false;
1408
}
1409

1410
bool Value::isUInt() const {
1,649✔
1411
  switch (type()) {
1,649✔
1412
  case intValue:
1,580✔
1413
#if defined(JSON_HAS_INT64)
1414
    return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
1,580✔
1415
#else
1416
    return value_.int_ >= 0;
1417
#endif
1418
  case uintValue:
21✔
1419
#if defined(JSON_HAS_INT64)
1420
    return value_.uint_ <= maxUInt;
21✔
1421
#else
1422
    return true;
1423
#endif
1424
  case realValue:
28✔
1425
    return value_.real_ >= 0 && value_.real_ <= maxUInt &&
28✔
1426
           IsIntegral(value_.real_);
1427
  default:
1428
    break;
1429
  }
1430
  return false;
1431
}
1432

1433
bool Value::isInt64() const {
56✔
1434
#if defined(JSON_HAS_INT64)
1435
  switch (type()) {
56✔
1436
  case intValue:
1437
    return true;
1438
  case uintValue:
13✔
1439
    return value_.uint_ <= UInt64(maxInt64);
13✔
1440
  case realValue:
15✔
1441
    // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
1442
    // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
1443
    // require the value to be strictly less than the limit.
1444
    // minInt64 is -2^63 which can be represented as a double, but since double
1445
    // values in its proximity are also rounded to -2^63, we require the value
1446
    // to be strictly greater than the limit to avoid returning 'true' for
1447
    // values that are not in the range
1448
    return value_.real_ > double(minInt64) && value_.real_ < double(maxInt64) &&
15✔
1449
           IsIntegral(value_.real_);
1450
  default:
1451
    break;
1452
  }
1453
#endif // JSON_HAS_INT64
1454
  return false;
1455
}
1456

1457
bool Value::isUInt64() const {
57✔
1458
#if defined(JSON_HAS_INT64)
1459
  switch (type()) {
57✔
1460
  case intValue:
20✔
1461
    return value_.int_ >= 0;
20✔
1462
  case uintValue:
1463
    return true;
1464
  case realValue:
15✔
1465
    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1466
    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1467
    // require the value to be strictly less than the limit.
1468
    return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
15✔
1469
           IsIntegral(value_.real_);
1470
  default:
1471
    break;
1472
  }
1473
#endif // JSON_HAS_INT64
1474
  return false;
1475
}
1476

1477
bool Value::isIntegral() const {
42✔
1478
  switch (type()) {
42✔
1479
  case intValue:
1480
  case uintValue:
1481
    return true;
1482
  case realValue:
14✔
1483
#if defined(JSON_HAS_INT64)
1484
    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
1485
    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
1486
    // require the value to be strictly less than the limit.
1487
    // minInt64 is -2^63 which can be represented as a double, but since double
1488
    // values in its proximity are also rounded to -2^63, we require the value
1489
    // to be strictly greater than the limit to avoid returning 'true' for
1490
    // values that are not in the range
1491
    return value_.real_ > double(minInt64) &&
13✔
1492
           value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
26✔
1493
#else
1494
    return value_.real_ >= minInt && value_.real_ <= maxUInt &&
1495
           IsIntegral(value_.real_);
1496
#endif // JSON_HAS_INT64
1497
  default:
1498
    break;
1499
  }
1500
  return false;
1501
}
1502

1503
bool Value::isDouble() const {
169✔
1504
  return type() == intValue || type() == uintValue || type() == realValue;
169✔
1505
}
1506

1507
bool Value::isNumeric() const { return isDouble(); }
119✔
1508

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

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

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

1515
Value::Comments::Comments(const Comments& that)
×
1516
    : ptr_{cloneUnique(that.ptr_)} {}
×
1517

1518
Value::Comments::Comments(Comments&& that) noexcept
125,028✔
1519
    : ptr_{std::move(that.ptr_)} {}
125,028✔
1520

1521
Value::Comments& Value::Comments::operator=(const Comments& that) {
253,265✔
1522
  ptr_ = cloneUnique(that.ptr_);
253,265✔
1523
  return *this;
253,265✔
1524
}
1525

1526
Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
493,417!
1527
  ptr_ = std::move(that.ptr_);
1528
  return *this;
493,417✔
1529
}
1530

1531
bool Value::Comments::has(CommentPlacement slot) const {
377,785✔
1532
  return ptr_ && !(*ptr_)[slot].empty();
377,785!
1533
}
1534

1535
String Value::Comments::get(CommentPlacement slot) const {
1,282!
1536
  if (!ptr_)
1,282!
1537
    return {};
1538
  return (*ptr_)[slot];
1,282!
1539
}
1540

1541
void Value::Comments::set(CommentPlacement slot, String comment) {
955✔
1542
  if (slot >= CommentPlacement::numberOfCommentPlacement)
955!
1543
    return;
1544
  if (!ptr_)
955✔
1545
    ptr_ = std::unique_ptr<Array>(new Array());
893✔
1546
  (*ptr_)[slot] = std::move(comment);
1,910!
1547
}
1548

1549
void Value::setComment(String comment, CommentPlacement placement) {
955!
1550
  if (!comment.empty() && (comment.back() == '\n')) {
955!
1551
    // Always discard trailing newline, to aid indentation.
1552
    comment.pop_back();
790✔
1553
  }
1554
  JSON_ASSERT_MESSAGE(
955!
1555
      comment.empty() || comment[0] == '/',
1556
      "in Json::Value::setComment(): Comments must start with /");
1557
  comments_.set(placement, std::move(comment));
955✔
1558
}
955✔
1559

1560
bool Value::hasComment(CommentPlacement placement) const {
377,785✔
1561
  return comments_.has(placement);
377,785✔
1562
}
1563

1564
String Value::getComment(CommentPlacement placement) const {
1,282✔
1565
  return comments_.get(placement);
1,282✔
1566
}
1567

1568
void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
113,818✔
1569

1570
void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
107,817✔
1571

1572
ptrdiff_t Value::getOffsetStart() const { return start_; }
19✔
1573

1574
ptrdiff_t Value::getOffsetLimit() const { return limit_; }
19✔
1575

1576
String Value::toStyledString() const {
5✔
1577
  StreamWriterBuilder builder;
5✔
1578

1579
  String out = this->hasComment(commentBefore) ? "\n" : "";
8✔
1580
  out += Json::writeString(builder, *this);
10✔
1581
  out += '\n';
1582

1583
  return out;
5✔
1584
}
5✔
1585

1586
Value::const_iterator Value::begin() const {
22✔
1587
  switch (type()) {
22✔
1588
  case arrayValue:
9✔
1589
  case objectValue:
1590
    if (value_.map_)
9!
1591
      return const_iterator(value_.map_->begin());
9✔
1592
    break;
1593
  default:
1594
    break;
1595
  }
1596
  return {};
13✔
1597
}
1598

1599
Value::const_iterator Value::end() const {
63✔
1600
  switch (type()) {
63✔
1601
  case arrayValue:
51✔
1602
  case objectValue:
1603
    if (value_.map_)
51!
1604
      return const_iterator(value_.map_->end());
51✔
1605
    break;
1606
  default:
1607
    break;
1608
  }
1609
  return {};
12✔
1610
}
1611

1612
Value::iterator Value::begin() {
37✔
1613
  switch (type()) {
37✔
1614
  case arrayValue:
24✔
1615
  case objectValue:
1616
    if (value_.map_)
24!
1617
      return iterator(value_.map_->begin());
24✔
1618
    break;
1619
  default:
1620
    break;
1621
  }
1622
  return iterator();
13✔
1623
}
1624

1625
Value::iterator Value::end() {
42✔
1626
  switch (type()) {
42✔
1627
  case arrayValue:
27✔
1628
  case objectValue:
1629
    if (value_.map_)
27!
1630
      return iterator(value_.map_->end());
27✔
1631
    break;
1632
  default:
1633
    break;
1634
  }
1635
  return iterator();
15✔
1636
}
1637

1638
// class PathArgument
1639
// //////////////////////////////////////////////////////////////////
1640

1641
PathArgument::PathArgument() = default;
36✔
1642

1643
PathArgument::PathArgument(ArrayIndex index)
4✔
1644
    : index_(index), kind_(kindIndex) {}
4✔
1645

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

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

1650
// class Path
1651
// //////////////////////////////////////////////////////////////////
1652

1653
Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
8✔
1654
           const PathArgument& a3, const PathArgument& a4,
1655
           const PathArgument& a5) {
1656
  InArgs in;
1657
  in.reserve(5);
8✔
1658
  in.push_back(&a1);
8✔
1659
  in.push_back(&a2);
8✔
1660
  in.push_back(&a3);
8✔
1661
  in.push_back(&a4);
8✔
1662
  in.push_back(&a5);
8✔
1663
  makePath(path, in);
8✔
1664
}
8✔
1665

1666
void Path::makePath(const String& path, const InArgs& in) {
8✔
1667
  const char* current = path.c_str();
1668
  const char* end = current + path.length();
8✔
1669
  auto itInArg = in.begin();
8✔
1670
  while (current != end) {
42✔
1671
    if (*current == '[') {
34✔
1672
      ++current;
4✔
1673
      if (*current == '%')
4✔
1674
        addPathInArg(path, in, itInArg, PathArgument::kindIndex);
2✔
1675
      else {
1676
        ArrayIndex index = 0;
1677
        for (; current != end && *current >= '0' && *current <= '9'; ++current)
4!
1678
          index = index * 10 + ArrayIndex(*current - '0');
2✔
1679
        args_.push_back(index);
4✔
1680
      }
1681
      if (current == end || *++current != ']')
4!
1682
        invalidPath(path, int(current - path.c_str()));
2✔
1683
    } else if (*current == '%') {
30✔
1684
      addPathInArg(path, in, itInArg, PathArgument::kindKey);
2✔
1685
      ++current;
2✔
1686
    } else if (*current == '.' || *current == ']') {
28✔
1687
      ++current;
18✔
1688
    } else {
1689
      const char* beginName = current;
1690
      while (current != end && !strchr("[.", *current))
88✔
1691
        ++current;
78✔
1692
      args_.push_back(String(beginName, current));
20✔
1693
    }
1694
  }
1695
}
8✔
1696

1697
void Path::addPathInArg(const String& /*path*/, const InArgs& in,
4!
1698
                        InArgs::const_iterator& itInArg,
1699
                        PathArgument::Kind kind) {
1700
  if (itInArg == in.end()) {
4!
1701
    // Error: missing argument %d
1702
  } else if ((*itInArg)->kind_ != kind) {
4!
1703
    // Error: bad argument type
1704
  } else {
1705
    args_.push_back(**itInArg++);
4✔
1706
  }
1707
}
4✔
1708

1709
void Path::invalidPath(const String& /*path*/, int /*location*/) {
2✔
1710
  // Error: invalid path.
1711
}
2✔
1712

1713
const Value& Path::resolve(const Value& root) const {
6✔
1714
  const Value* node = &root;
1715
  for (const auto& arg : args_) {
14✔
1716
    if (arg.kind_ == PathArgument::kindIndex) {
12✔
1717
      if (!node->isArray() || !node->isValidIndex(arg.index_)) {
2!
1718
        // Error: unable to resolve path (array value expected at position... )
1719
        return Value::nullSingleton();
1✔
1720
      }
1721
      node = &((*node)[arg.index_]);
1✔
1722
    } else if (arg.kind_ == PathArgument::kindKey) {
10!
1723
      if (!node->isObject()) {
10✔
1724
        // Error: unable to resolve path (object value expected at position...)
1725
        return Value::nullSingleton();
1✔
1726
      }
1727
      node = &((*node)[arg.key_]);
9✔
1728
      if (node == &Value::nullSingleton()) {
9✔
1729
        // Error: unable to resolve path (object has no member named '' at
1730
        // position...)
1731
        return Value::nullSingleton();
2✔
1732
      }
1733
    }
1734
  }
1735
  return *node;
1736
}
1737

1738
Value Path::resolve(const Value& root, const Value& defaultValue) const {
6✔
1739
  const Value* node = &root;
1740
  for (const auto& arg : args_) {
14✔
1741
    if (arg.kind_ == PathArgument::kindIndex) {
12✔
1742
      if (!node->isArray() || !node->isValidIndex(arg.index_))
3✔
1743
        return defaultValue;
2✔
1744
      node = &((*node)[arg.index_]);
1✔
1745
    } else if (arg.kind_ == PathArgument::kindKey) {
9!
1746
      if (!node->isObject())
9✔
1747
        return defaultValue;
1✔
1748
      node = &((*node)[arg.key_]);
8✔
1749
      if (node == &Value::nullSingleton())
8✔
1750
        return defaultValue;
1✔
1751
    }
1752
  }
1753
  return *node;
2✔
1754
}
1755

1756
Value& Path::make(Value& root) const {
2✔
1757
  Value* node = &root;
1758
  for (const auto& arg : args_) {
6✔
1759
    if (arg.kind_ == PathArgument::kindIndex) {
4✔
1760
      if (!node->isArray()) {
1✔
1761
        // Error: node is not an array at position ...
1762
      }
1763
      node = &((*node)[arg.index_]);
1✔
1764
    } else if (arg.kind_ == PathArgument::kindKey) {
3!
1765
      if (!node->isObject()) {
3✔
1766
        // Error: node is not an object at position...
1767
      }
1768
      node = &((*node)[arg.key_]);
3✔
1769
    }
1770
  }
1771
  return *node;
2✔
1772
}
1773

1774
} // 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