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

open-source-parsers / jsoncpp / 10784463077

10 Sep 2024 02:06AM CUT coverage: 95.536%. Remained the same
10784463077

push

github

web-flow
Update meson.yml

5307 of 5555 relevant lines covered (95.54%)

11962.7 hits per line

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

95.01
/src/lib_json/json_reader.cpp
1
// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors
2
// Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
3
// Distributed under MIT license, or public domain if desired and
4
// recognized in your jurisdiction.
5
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
6

7
#if !defined(JSON_IS_AMALGAMATION)
8
#include "json_tool.h"
9
#include <json/assertions.h>
10
#include <json/reader.h>
11
#include <json/value.h>
12
#endif // if !defined(JSON_IS_AMALGAMATION)
13
#include <algorithm>
14
#include <cassert>
15
#include <cmath>
16
#include <cstring>
17
#include <iostream>
18
#include <istream>
19
#include <limits>
20
#include <memory>
21
#include <set>
22
#include <sstream>
23
#include <utility>
24

25
#include <cstdio>
26
#if __cplusplus >= 201103L
27

28
#if !defined(sscanf)
29
#define sscanf std::sscanf
30
#endif
31

32
#endif //__cplusplus
33

34
#if defined(_MSC_VER)
35
#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
36
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
37
#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
38
#endif //_MSC_VER
39

40
#if defined(_MSC_VER)
41
// Disable warning about strdup being deprecated.
42
#pragma warning(disable : 4996)
43
#endif
44

45
// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
46
// time to change the stack limit
47
#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
48
#define JSONCPP_DEPRECATED_STACK_LIMIT 1000
49
#endif
50

51
static size_t const stackLimit_g =
52
    JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
53

54
namespace Json {
55

56
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
57
using CharReaderPtr = std::unique_ptr<CharReader>;
58
#else
59
using CharReaderPtr = std::auto_ptr<CharReader>;
60
#endif
61

62
// Implementation of class Features
63
// ////////////////////////////////
64

65
Features::Features() = default;
606✔
66

67
Features Features::all() { return {}; }
15✔
68

69
Features Features::strictMode() {
100✔
70
  Features features;
100✔
71
  features.allowComments_ = false;
100✔
72
  features.strictRoot_ = true;
100✔
73
  features.allowDroppedNullPlaceholders_ = false;
100✔
74
  features.allowNumericKeys_ = false;
100✔
75
  return features;
100✔
76
}
77

78
// Implementation of class Reader
79
// ////////////////////////////////
80

81
bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
184✔
82
  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
347✔
83
}
84

85
// Class Reader
86
// //////////////////////////////////////////////////////////////////
87

88
Reader::Reader() : features_(Features::all()) {}
30✔
89

90
Reader::Reader(const Features& features) : features_(features) {}
1,372✔
91

92
bool Reader::parse(const std::string& document, Value& root,
25✔
93
                   bool collectComments) {
94
  document_.assign(document.begin(), document.end());
25✔
95
  const char* begin = document_.c_str();
96
  const char* end = begin + document_.length();
25✔
97
  return parse(begin, end, root, collectComments);
25✔
98
}
99

100
bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
1✔
101
  // std::istream_iterator<char> begin(is);
102
  // std::istream_iterator<char> end;
103
  // Those would allow streamed input from a file, if parse() were a
104
  // template function.
105

106
  // Since String is reference-counted, this at least does not
107
  // create an extra copy.
108
  String doc(std::istreambuf_iterator<char>(is), {});
109
  return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
2✔
110
}
111

112
bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
710✔
113
                   bool collectComments) {
114
  if (!features_.allowComments_) {
710✔
115
    collectComments = false;
116
  }
117

118
  begin_ = beginDoc;
710✔
119
  end_ = endDoc;
710✔
120
  collectComments_ = collectComments;
710✔
121
  current_ = begin_;
710✔
122
  lastValueEnd_ = nullptr;
710✔
123
  lastValue_ = nullptr;
710✔
124
  commentsBefore_.clear();
125
  errors_.clear();
710✔
126
  while (!nodes_.empty())
721✔
127
    nodes_.pop();
11✔
128
  nodes_.push(&root);
710✔
129

130
  bool successful = readValue();
710✔
131
  Token token;
132
  readTokenSkippingComments(token);
710✔
133
  if (collectComments_ && !commentsBefore_.empty())
710✔
134
    root.setComment(commentsBefore_, commentAfter);
26✔
135
  if (features_.strictRoot_) {
710✔
136
    if (!root.isArray() && !root.isObject()) {
1✔
137
      // Set error location to start of doc, ideally should be first token found
138
      // in doc
139
      token.type_ = tokenError;
1✔
140
      token.start_ = beginDoc;
1✔
141
      token.end_ = endDoc;
1✔
142
      addError(
1✔
143
          "A valid JSON document must be either an array or an object value.",
144
          token);
145
      return false;
1✔
146
    }
147
  }
148
  return successful;
149
}
150

151
bool Reader::readValue() {
53,560✔
152
  // readValue() may call itself only if it calls readObject() or ReadArray().
153
  // These methods execute nodes_.push() just before and nodes_.pop)() just
154
  // after calling readValue(). parse() executes one nodes_.push(), so > instead
155
  // of >=.
156
  if (nodes_.size() > stackLimit_g)
53,560✔
157
    throwRuntimeError("Exceeded stackLimit in readValue().");
×
158

159
  Token token;
160
  readTokenSkippingComments(token);
53,560✔
161
  bool successful = true;
162

163
  if (collectComments_ && !commentsBefore_.empty()) {
53,560✔
164
    currentValue().setComment(commentsBefore_, commentBefore);
1,191✔
165
    commentsBefore_.clear();
166
  }
167

168
  switch (token.type_) {
53,560✔
169
  case tokenObjectBegin:
244✔
170
    successful = readObject(token);
244✔
171
    currentValue().setOffsetLimit(current_ - begin_);
244✔
172
    break;
173
  case tokenArrayBegin:
189✔
174
    successful = readArray(token);
189✔
175
    currentValue().setOffsetLimit(current_ - begin_);
189✔
176
    break;
177
  case tokenNumber:
52,648✔
178
    successful = decodeNumber(token);
52,648✔
179
    break;
180
  case tokenString:
374✔
181
    successful = decodeString(token);
374✔
182
    break;
183
  case tokenTrue: {
26✔
184
    Value v(true);
26✔
185
    currentValue().swapPayload(v);
26✔
186
    currentValue().setOffsetStart(token.start_ - begin_);
26✔
187
    currentValue().setOffsetLimit(token.end_ - begin_);
26✔
188
  } break;
26✔
189
  case tokenFalse: {
25✔
190
    Value v(false);
25✔
191
    currentValue().swapPayload(v);
25✔
192
    currentValue().setOffsetStart(token.start_ - begin_);
25✔
193
    currentValue().setOffsetLimit(token.end_ - begin_);
25✔
194
  } break;
25✔
195
  case tokenNull: {
49✔
196
    Value v;
49✔
197
    currentValue().swapPayload(v);
49✔
198
    currentValue().setOffsetStart(token.start_ - begin_);
49✔
199
    currentValue().setOffsetLimit(token.end_ - begin_);
49✔
200
  } break;
49✔
201
  case tokenArraySeparator:
×
202
  case tokenObjectEnd:
203
  case tokenArrayEnd:
204
    if (features_.allowDroppedNullPlaceholders_) {
×
205
      // "Un-read" the current token and mark the current value as a null
206
      // token.
207
      current_--;
×
208
      Value v;
×
209
      currentValue().swapPayload(v);
×
210
      currentValue().setOffsetStart(current_ - begin_ - 1);
×
211
      currentValue().setOffsetLimit(current_ - begin_);
×
212
      break;
213
    } // Else, fall through...
×
214
  default:
215
    currentValue().setOffsetStart(token.start_ - begin_);
5✔
216
    currentValue().setOffsetLimit(token.end_ - begin_);
5✔
217
    return addError("Syntax error: value, object or array expected.", token);
10✔
218
  }
219

220
  if (collectComments_) {
53,555✔
221
    lastValueEnd_ = current_;
53,554✔
222
    lastValue_ = &currentValue();
53,554✔
223
  }
224

225
  return successful;
226
}
227

228
bool Reader::readTokenSkippingComments(Token& token) {
107,540✔
229
  bool success = readToken(token);
107,540✔
230
  if (features_.allowComments_) {
107,540✔
231
    while (success && token.type_ == tokenComment) {
108,107✔
232
      success = readToken(token);
569✔
233
    }
234
  }
235
  return success;
107,540✔
236
}
237

238
bool Reader::readToken(Token& token) {
108,563✔
239
  skipSpaces();
108,563✔
240
  token.start_ = current_;
108,563✔
241
  Char c = getNextChar();
108,563✔
242
  bool ok = true;
243
  switch (c) {
108,563✔
244
  case '{':
244✔
245
    token.type_ = tokenObjectBegin;
244✔
246
    break;
247
  case '}':
242✔
248
    token.type_ = tokenObjectEnd;
242✔
249
    break;
250
  case '[':
189✔
251
    token.type_ = tokenArrayBegin;
189✔
252
    break;
253
  case ']':
188✔
254
    token.type_ = tokenArrayEnd;
188✔
255
    break;
256
  case '"':
792✔
257
    token.type_ = tokenString;
792✔
258
    ok = readString();
792✔
259
    break;
792✔
260
  case '/':
569✔
261
    token.type_ = tokenComment;
569✔
262
    ok = readComment();
569✔
263
    break;
569✔
264
  case '0':
52,649✔
265
  case '1':
266
  case '2':
267
  case '3':
268
  case '4':
269
  case '5':
270
  case '6':
271
  case '7':
272
  case '8':
273
  case '9':
274
  case '-':
275
    token.type_ = tokenNumber;
52,649✔
276
    readNumber();
52,649✔
277
    break;
278
  case 't':
26✔
279
    token.type_ = tokenTrue;
26✔
280
    ok = match("rue", 3);
26✔
281
    break;
26✔
282
  case 'f':
27✔
283
    token.type_ = tokenFalse;
27✔
284
    ok = match("alse", 4);
27✔
285
    break;
27✔
286
  case 'n':
52✔
287
    token.type_ = tokenNull;
52✔
288
    ok = match("ull", 3);
52✔
289
    break;
52✔
290
  case ',':
52,443✔
291
    token.type_ = tokenArraySeparator;
52,443✔
292
    break;
293
  case ':':
417✔
294
    token.type_ = tokenMemberSeparator;
417✔
295
    break;
296
  case 0:
717✔
297
    token.type_ = tokenEndOfStream;
717✔
298
    break;
299
  default:
300
    ok = false;
301
    break;
302
  }
303
  if (!ok)
1,466✔
304
    token.type_ = tokenError;
13✔
305
  token.end_ = current_;
108,563✔
306
  return ok;
108,563✔
307
}
308

309
void Reader::skipSpaces() {
108,752✔
310
  while (current_ != end_) {
226,612✔
311
    Char c = *current_;
225,895✔
312
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
225,895✔
313
      ++current_;
117,860✔
314
    else
315
      break;
316
  }
317
}
108,752✔
318

319
bool Reader::match(const Char* pattern, int patternLength) {
105✔
320
  if (end_ - current_ < patternLength)
105✔
321
    return false;
322
  int index = patternLength;
323
  while (index--)
429✔
324
    if (current_[index] != pattern[index])
329✔
325
      return false;
326
  current_ += patternLength;
100✔
327
  return true;
100✔
328
}
329

330
bool Reader::readComment() {
569✔
331
  Location commentBegin = current_ - 1;
569✔
332
  Char c = getNextChar();
569✔
333
  bool successful = false;
334
  if (c == '*')
569✔
335
    successful = readCStyleComment();
73✔
336
  else if (c == '/')
496✔
337
    successful = readCppStyleComment();
496✔
338
  if (!successful)
569✔
339
    return false;
×
340

341
  if (collectComments_) {
569✔
342
    CommentPlacement placement = commentBefore;
343
    if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
569✔
344
      if (c != '*' || !containsNewLine(commentBegin, current_))
50✔
345
        placement = commentAfterOnSameLine;
346
    }
347

348
    addComment(commentBegin, current_, placement);
569✔
349
  }
350
  return true;
351
}
352

353
String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
569✔
354
  String normalized;
355
  normalized.reserve(static_cast<size_t>(end - begin));
569✔
356
  Reader::Location current = begin;
357
  while (current != end) {
21,596✔
358
    char c = *current++;
21,027✔
359
    if (c == '\r') {
21,027✔
360
      if (current != end && *current == '\n')
2✔
361
        // convert dos EOL
362
        ++current;
1✔
363
      // convert Mac EOL
364
      normalized += '\n';
365
    } else {
366
      normalized += c;
21,025✔
367
    }
368
  }
369
  return normalized;
569✔
370
}
371

372
void Reader::addComment(Location begin, Location end,
569✔
373
                        CommentPlacement placement) {
374
  assert(collectComments_);
569✔
375
  const String& normalized = normalizeEOL(begin, end);
569✔
376
  if (placement == commentAfterOnSameLine) {
569✔
377
    assert(lastValue_ != nullptr);
50✔
378
    lastValue_->setComment(normalized, placement);
100✔
379
  } else {
380
    commentsBefore_ += normalized;
519✔
381
  }
382
}
569✔
383

384
bool Reader::readCStyleComment() {
73✔
385
  while ((current_ + 1) < end_) {
2,419✔
386
    Char c = getNextChar();
2,419✔
387
    if (c == '*' && *current_ == '/')
2,419✔
388
      break;
389
  }
390
  return getNextChar() == '/';
73✔
391
}
392

393
bool Reader::readCppStyleComment() {
496✔
394
  while (current_ != end_) {
17,397✔
395
    Char c = getNextChar();
17,397✔
396
    if (c == '\n')
17,397✔
397
      break;
398
    if (c == '\r') {
16,903✔
399
      // Consume DOS EOL. It will be normalized in addComment.
400
      if (current_ != end_ && *current_ == '\n')
2✔
401
        getNextChar();
1✔
402
      // Break on Moc OS 9 EOL.
403
      break;
404
    }
405
  }
406
  return true;
496✔
407
}
408

409
void Reader::readNumber() {
52,649✔
410
  Location p = current_;
52,649✔
411
  char c = '0'; // stopgap for already consumed character
412
  // integral part
413
  while (c >= '0' && c <= '9')
234,907✔
414
    c = (current_ = p) < end_ ? *p++ : '\0';
182,258✔
415
  // fractional part
416
  if (c == '.') {
52,649✔
417
    c = (current_ = p) < end_ ? *p++ : '\0';
91✔
418
    while (c >= '0' && c <= '9')
674✔
419
      c = (current_ = p) < end_ ? *p++ : '\0';
583✔
420
  }
421
  // exponential part
422
  if (c == 'e' || c == 'E') {
52,649✔
423
    c = (current_ = p) < end_ ? *p++ : '\0';
67✔
424
    if (c == '+' || c == '-')
67✔
425
      c = (current_ = p) < end_ ? *p++ : '\0';
55✔
426
    while (c >= '0' && c <= '9')
225✔
427
      c = (current_ = p) < end_ ? *p++ : '\0';
158✔
428
  }
429
}
52,649✔
430

431
bool Reader::readString() {
792✔
432
  Char c = '\0';
433
  while (current_ != end_) {
30,369✔
434
    c = getNextChar();
30,369✔
435
    if (c == '\\')
30,369✔
436
      getNextChar();
1,152✔
437
    else if (c == '"')
29,217✔
438
      break;
439
  }
440
  return c == '"';
792✔
441
}
442

443
bool Reader::readObject(Token& token) {
244✔
444
  Token tokenName;
445
  String name;
446
  Value init(objectValue);
244✔
447
  currentValue().swapPayload(init);
244✔
448
  currentValue().setOffsetStart(token.start_ - begin_);
244✔
449
  while (readTokenSkippingComments(tokenName)) {
429✔
450
    if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
429✔
451
      return true;
243✔
452
    name.clear();
453
    if (tokenName.type_ == tokenString) {
417✔
454
      if (!decodeString(tokenName, name))
415✔
455
        return recoverFromError(tokenObjectEnd);
×
456
    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
2✔
457
      Value numberName;
1✔
458
      if (!decodeNumber(tokenName, numberName))
1✔
459
        return recoverFromError(tokenObjectEnd);
×
460
      name = numberName.asString();
1✔
461
    } else {
1✔
462
      break;
463
    }
464

465
    Token colon;
466
    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
416✔
467
      return addErrorAndRecover("Missing ':' after object member name", colon,
2✔
468
                                tokenObjectEnd);
469
    }
470
    Value& value = currentValue()[name];
415✔
471
    nodes_.push(&value);
415✔
472
    bool ok = readValue();
415✔
473
    nodes_.pop();
415✔
474
    if (!ok) // error already set
415✔
475
      return recoverFromError(tokenObjectEnd);
5✔
476

477
    Token comma;
478
    if (!readTokenSkippingComments(comma) ||
410✔
479
        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
410✔
480
      return addErrorAndRecover("Missing ',' or '}' in object declaration",
2✔
481
                                comma, tokenObjectEnd);
482
    }
483
    if (comma.type_ == tokenObjectEnd)
409✔
484
      return true;
485
  }
486
  return addErrorAndRecover("Missing '}' or object member name", tokenName,
2✔
487
                            tokenObjectEnd);
488
}
244✔
489

490
bool Reader::readArray(Token& token) {
189✔
491
  Value init(arrayValue);
189✔
492
  currentValue().swapPayload(init);
189✔
493
  currentValue().setOffsetStart(token.start_ - begin_);
189✔
494
  skipSpaces();
189✔
495
  if (current_ != end_ && *current_ == ']') // empty array
189✔
496
  {
497
    Token endArray;
498
    readToken(endArray);
12✔
499
    return true;
500
  }
501
  int index = 0;
502
  for (;;) {
503
    Value& value = currentValue()[index++];
52,435✔
504
    nodes_.push(&value);
52,435✔
505
    bool ok = readValue();
52,435✔
506
    nodes_.pop();
52,435✔
507
    if (!ok) // error already set
52,435✔
508
      return recoverFromError(tokenArrayEnd);
6✔
509

510
    Token currentToken;
511
    // Accept Comment after last item in the array.
512
    ok = readTokenSkippingComments(currentToken);
52,431✔
513
    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
52,431✔
514
                         currentToken.type_ != tokenArrayEnd);
52,431✔
515
    if (!ok || badTokenType) {
52,431✔
516
      return addErrorAndRecover("Missing ',' or ']' in array declaration",
4✔
517
                                currentToken, tokenArrayEnd);
518
    }
519
    if (currentToken.type_ == tokenArrayEnd)
52,429✔
520
      break;
521
  }
52,258✔
522
  return true;
171✔
523
}
189✔
524

525
bool Reader::decodeNumber(Token& token) {
52,648✔
526
  Value decoded;
52,648✔
527
  if (!decodeNumber(token, decoded))
52,648✔
528
    return false;
529
  currentValue().swapPayload(decoded);
52,648✔
530
  currentValue().setOffsetStart(token.start_ - begin_);
52,648✔
531
  currentValue().setOffsetLimit(token.end_ - begin_);
52,648✔
532
  return true;
533
}
52,648✔
534

535
bool Reader::decodeNumber(Token& token, Value& decoded) {
52,649✔
536
  // Attempts to parse the number as an integer. If the number is
537
  // larger than the maximum supported value of an integer then
538
  // we decode the number as a double.
539
  Location current = token.start_;
52,649✔
540
  bool isNegative = *current == '-';
52,649✔
541
  if (isNegative)
52,649✔
542
    ++current;
133✔
543
  // TODO: Help the compiler do the div and mod at compile time or get rid of
544
  // them.
545
  Value::LargestUInt maxIntegerValue =
546
      isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
52,649✔
547
                 : Value::maxLargestUInt;
548
  Value::LargestUInt threshold = maxIntegerValue / 10;
52,649✔
549
  Value::LargestUInt value = 0;
550
  while (current < token.end_) {
234,756✔
551
    Char c = *current++;
182,252✔
552
    if (c < '0' || c > '9')
182,252✔
553
      return decodeDouble(token, decoded);
127✔
554
    auto digit(static_cast<Value::UInt>(c - '0'));
182,125✔
555
    if (value >= threshold) {
182,125✔
556
      // We've hit or exceeded the max value divided by 10 (rounded down). If
557
      // a) we've only just touched the limit, b) this is the last digit, and
558
      // c) it's small enough to fit in that rounding delta, we're okay.
559
      // Otherwise treat this number as a double to avoid overflow.
560
      if (value > threshold || current != token.end_ ||
42✔
561
          digit > maxIntegerValue % 10) {
30✔
562
        return decodeDouble(token, decoded);
18✔
563
      }
564
    }
565
    value = value * 10 + digit;
182,107✔
566
  }
567
  if (isNegative && value == maxIntegerValue)
52,504✔
568
    decoded = Value::minLargestInt;
12✔
569
  else if (isNegative)
52,492✔
570
    decoded = -Value::LargestInt(value);
72✔
571
  else if (value <= Value::LargestUInt(Value::maxInt))
52,420✔
572
    decoded = Value::LargestInt(value);
52,360✔
573
  else
574
    decoded = value;
60✔
575
  return true;
576
}
577

578
bool Reader::decodeDouble(Token& token) {
×
579
  Value decoded;
×
580
  if (!decodeDouble(token, decoded))
×
581
    return false;
582
  currentValue().swapPayload(decoded);
×
583
  currentValue().setOffsetStart(token.start_ - begin_);
×
584
  currentValue().setOffsetLimit(token.end_ - begin_);
×
585
  return true;
586
}
×
587

588
bool Reader::decodeDouble(Token& token, Value& decoded) {
145✔
589
  double value = 0;
145✔
590
  String buffer(token.start_, token.end_);
145✔
591
  IStringStream is(buffer);
145✔
592
  if (!(is >> value)) {
145✔
593
    if (value == std::numeric_limits<double>::max())
24✔
594
      value = std::numeric_limits<double>::infinity();
12✔
595
    else if (value == std::numeric_limits<double>::lowest())
12✔
596
      value = -std::numeric_limits<double>::infinity();
12✔
597
    else if (!std::isinf(value))
×
598
      return addError(
×
599
          "'" + String(token.start_, token.end_) + "' is not a number.", token);
×
600
  }
601
  decoded = value;
145✔
602
  return true;
145✔
603
}
145✔
604

605
bool Reader::decodeString(Token& token) {
374✔
606
  String decoded_string;
607
  if (!decodeString(token, decoded_string))
374✔
608
    return false;
609
  Value decoded(decoded_string);
369✔
610
  currentValue().swapPayload(decoded);
369✔
611
  currentValue().setOffsetStart(token.start_ - begin_);
369✔
612
  currentValue().setOffsetLimit(token.end_ - begin_);
369✔
613
  return true;
614
}
369✔
615

616
bool Reader::decodeString(Token& token, String& decoded) {
789✔
617
  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
789✔
618
  Location current = token.start_ + 1; // skip '"'
789✔
619
  Location end = token.end_ - 1;       // do not include '"'
789✔
620
  while (current != end) {
29,861✔
621
    Char c = *current++;
29,077✔
622
    if (c == '"')
29,077✔
623
      break;
624
    if (c == '\\') {
29,077✔
625
      if (current == end)
1,138✔
626
        return addError("Empty escape sequence in string", token, current);
×
627
      Char escape = *current++;
1,138✔
628
      switch (escape) {
1,138✔
629
      case '"':
630
        decoded += '"';
631
        break;
632
      case '/':
633
        decoded += '/';
634
        break;
635
      case '\\':
636
        decoded += '\\';
637
        break;
638
      case 'b':
639
        decoded += '\b';
640
        break;
641
      case 'f':
642
        decoded += '\f';
643
        break;
644
      case 'n':
645
        decoded += '\n';
646
        break;
647
      case 'r':
648
        decoded += '\r';
649
        break;
650
      case 't':
651
        decoded += '\t';
652
        break;
653
      case 'u': {
103✔
654
        unsigned int unicode;
655
        if (!decodeUnicodeCodePoint(token, current, end, unicode))
103✔
656
          return false;
4✔
657
        decoded += codePointToUTF8(unicode);
99✔
658
      } break;
99✔
659
      default:
1✔
660
        return addError("Bad escape sequence in string", token, current);
2✔
661
      }
662
    } else {
663
      decoded += c;
27,939✔
664
    }
665
  }
666
  return true;
667
}
668

669
bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
103✔
670
                                    Location end, unsigned int& unicode) {
671

672
  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
103✔
673
    return false;
674
  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
101✔
675
    // surrogate pairs
676
    if (end - current < 6)
15✔
677
      return addError(
2✔
678
          "additional six characters expected to parse unicode surrogate pair.",
679
          token, current);
680
    if (*(current++) == '\\' && *(current++) == 'u') {
14✔
681
      unsigned int surrogatePair;
682
      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
13✔
683
        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
13✔
684
      } else
685
        return false;
×
686
    } else
687
      return addError("expecting another \\u token to begin the second half of "
2✔
688
                      "a unicode surrogate pair",
689
                      token, current);
690
  }
691
  return true;
692
}
693

694
bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
116✔
695
                                         Location end,
696
                                         unsigned int& ret_unicode) {
697
  if (end - current < 4)
116✔
698
    return addError(
2✔
699
        "Bad unicode escape sequence in string: four digits expected.", token,
700
        current);
701
  int unicode = 0;
702
  for (int index = 0; index < 4; ++index) {
573✔
703
    Char c = *current++;
459✔
704
    unicode *= 16;
459✔
705
    if (c >= '0' && c <= '9')
459✔
706
      unicode += c - '0';
342✔
707
    else if (c >= 'a' && c <= 'f')
117✔
708
      unicode += c - 'a' + 10;
74✔
709
    else if (c >= 'A' && c <= 'F')
43✔
710
      unicode += c - 'A' + 10;
42✔
711
    else
712
      return addError(
2✔
713
          "Bad unicode escape sequence in string: hexadecimal digit expected.",
714
          token, current);
715
  }
716
  ret_unicode = static_cast<unsigned int>(unicode);
114✔
717
  return true;
114✔
718
}
719

720
bool Reader::addError(const String& message, Token& token, Location extra) {
16✔
721
  ErrorInfo info;
722
  info.token_ = token;
16✔
723
  info.message_ = message;
724
  info.extra_ = extra;
16✔
725
  errors_.push_back(info);
16✔
726
  return false;
16✔
727
}
728

729
bool Reader::recoverFromError(TokenType skipUntilToken) {
14✔
730
  size_t const errorCount = errors_.size();
731
  Token skip;
732
  for (;;) {
733
    if (!readToken(skip))
26✔
734
      errors_.resize(errorCount); // discard errors caused by recovery
10✔
735
    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
26✔
736
      break;
737
  }
738
  errors_.resize(errorCount);
14✔
739
  return false;
14✔
740
}
741

742
bool Reader::addErrorAndRecover(const String& message, Token& token,
5✔
743
                                TokenType skipUntilToken) {
744
  addError(message, token);
5✔
745
  return recoverFromError(skipUntilToken);
5✔
746
}
747

748
Value& Reader::currentValue() { return *(nodes_.top()); }
267,461✔
749

750
Reader::Char Reader::getNextChar() {
160,543✔
751
  if (current_ == end_)
160,543✔
752
    return 0;
753
  return *current_++;
159,826✔
754
}
755

756
void Reader::getLocationLineAndColumn(Location location, int& line,
24✔
757
                                      int& column) const {
758
  Location current = begin_;
24✔
759
  Location lastLineStart = current;
760
  line = 0;
24✔
761
  while (current < location && current != end_) {
263✔
762
    Char c = *current++;
239✔
763
    if (c == '\r') {
239✔
764
      if (current != end_ && *current == '\n')
×
765
        ++current;
×
766
      lastLineStart = current;
767
      ++line;
×
768
    } else if (c == '\n') {
239✔
769
      lastLineStart = current;
770
      ++line;
×
771
    }
772
  }
773
  // column & line start at 1
774
  column = int(location - lastLineStart) + 1;
24✔
775
  ++line;
24✔
776
}
24✔
777

778
String Reader::getLocationLineAndColumn(Location location) const {
24✔
779
  int line, column;
780
  getLocationLineAndColumn(location, line, column);
24✔
781
  char buffer[18 + 16 + 16 + 1];
782
  jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
24✔
783
  return buffer;
24✔
784
}
785

786
// Deprecated. Preserved for backward compatibility
787
String Reader::getFormatedErrorMessages() const {
×
788
  return getFormattedErrorMessages();
×
789
}
790

791
String Reader::getFormattedErrorMessages() const {
19✔
792
  String formattedMessage;
793
  for (const auto& error : errors_) {
37✔
794
    formattedMessage +=
795
        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
36✔
796
    formattedMessage += "  " + error.message_ + "\n";
36✔
797
    if (error.extra_)
18✔
798
      formattedMessage +=
799
          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
12✔
800
  }
801
  return formattedMessage;
19✔
802
}
803

804
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
17✔
805
  std::vector<Reader::StructuredError> allErrors;
806
  for (const auto& error : errors_) {
33✔
807
    Reader::StructuredError structured;
808
    structured.offset_start = error.token_.start_ - begin_;
16✔
809
    structured.offset_limit = error.token_.end_ - begin_;
16✔
810
    structured.message = error.message_;
16✔
811
    allErrors.push_back(structured);
16✔
812
  }
813
  return allErrors;
17✔
814
}
×
815

816
bool Reader::pushError(const Value& value, const String& message) {
1✔
817
  ptrdiff_t const length = end_ - begin_;
1✔
818
  if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
1✔
819
    return false;
×
820
  Token token;
821
  token.type_ = tokenError;
822
  token.start_ = begin_ + value.getOffsetStart();
1✔
823
  token.end_ = begin_ + value.getOffsetLimit();
1✔
824
  ErrorInfo info;
825
  info.token_ = token;
1✔
826
  info.message_ = message;
827
  info.extra_ = nullptr;
1✔
828
  errors_.push_back(info);
1✔
829
  return true;
830
}
831

832
bool Reader::pushError(const Value& value, const String& message,
1✔
833
                       const Value& extra) {
834
  ptrdiff_t const length = end_ - begin_;
1✔
835
  if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
2✔
836
      extra.getOffsetLimit() > length)
1✔
837
    return false;
×
838
  Token token;
839
  token.type_ = tokenError;
840
  token.start_ = begin_ + value.getOffsetStart();
1✔
841
  token.end_ = begin_ + value.getOffsetLimit();
1✔
842
  ErrorInfo info;
843
  info.token_ = token;
1✔
844
  info.message_ = message;
845
  info.extra_ = begin_ + extra.getOffsetStart();
1✔
846
  errors_.push_back(info);
1✔
847
  return true;
848
}
849

850
bool Reader::good() const { return errors_.empty(); }
×
851

852
// Originally copied from the Features class (now deprecated), used internally
853
// for features implementation.
854
class OurFeatures {
855
public:
856
  static OurFeatures all();
857
  bool allowComments_;
858
  bool allowTrailingCommas_;
859
  bool strictRoot_;
860
  bool allowDroppedNullPlaceholders_;
861
  bool allowNumericKeys_;
862
  bool allowSingleQuotes_;
863
  bool failIfExtra_;
864
  bool rejectDupKeys_;
865
  bool allowSpecialFloats_;
866
  bool skipBom_;
867
  size_t stackLimit_;
868
}; // OurFeatures
869

870
OurFeatures OurFeatures::all() { return {}; }
894✔
871

872
// Implementation of class Reader
873
// ////////////////////////////////
874

875
// Originally copied from the Reader class (now deprecated), used internally
876
// for implementing JSON reading.
877
class OurReader {
878
public:
879
  using Char = char;
880
  using Location = const Char*;
881

882
  explicit OurReader(OurFeatures const& features);
883
  bool parse(const char* beginDoc, const char* endDoc, Value& root,
884
             bool collectComments = true);
885
  String getFormattedErrorMessages() const;
886
  std::vector<CharReader::StructuredError> getStructuredErrors() const;
887

888
private:
889
  OurReader(OurReader const&);      // no impl
890
  void operator=(OurReader const&); // no impl
891

892
  enum TokenType {
893
    tokenEndOfStream = 0,
894
    tokenObjectBegin,
895
    tokenObjectEnd,
896
    tokenArrayBegin,
897
    tokenArrayEnd,
898
    tokenString,
899
    tokenNumber,
900
    tokenTrue,
901
    tokenFalse,
902
    tokenNull,
903
    tokenNaN,
904
    tokenPosInf,
905
    tokenNegInf,
906
    tokenArraySeparator,
907
    tokenMemberSeparator,
908
    tokenComment,
909
    tokenError
910
  };
911

912
  class Token {
913
  public:
914
    TokenType type_;
915
    Location start_;
916
    Location end_;
917
  };
918

919
  class ErrorInfo {
156✔
920
  public:
921
    Token token_;
922
    String message_;
923
    Location extra_;
924
  };
925

926
  using Errors = std::deque<ErrorInfo>;
927

928
  bool readToken(Token& token);
929
  bool readTokenSkippingComments(Token& token);
930
  void skipSpaces();
931
  void skipBom(bool skipBom);
932
  bool match(const Char* pattern, int patternLength);
933
  bool readComment();
934
  bool readCStyleComment(bool* containsNewLineResult);
935
  bool readCppStyleComment();
936
  bool readString();
937
  bool readStringSingleQuote();
938
  bool readNumber(bool checkInf);
939
  bool readValue();
940
  bool readObject(Token& token);
941
  bool readArray(Token& token);
942
  bool decodeNumber(Token& token);
943
  bool decodeNumber(Token& token, Value& decoded);
944
  bool decodeString(Token& token);
945
  bool decodeString(Token& token, String& decoded);
946
  bool decodeDouble(Token& token);
947
  bool decodeDouble(Token& token, Value& decoded);
948
  bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
949
                              unsigned int& unicode);
950
  bool decodeUnicodeEscapeSequence(Token& token, Location& current,
951
                                   Location end, unsigned int& unicode);
952
  bool addError(const String& message, Token& token, Location extra = nullptr);
953
  bool recoverFromError(TokenType skipUntilToken);
954
  bool addErrorAndRecover(const String& message, Token& token,
955
                          TokenType skipUntilToken);
956
  void skipUntilSpace();
957
  Value& currentValue();
958
  Char getNextChar();
959
  void getLocationLineAndColumn(Location location, int& line,
960
                                int& column) const;
961
  String getLocationLineAndColumn(Location location) const;
962
  void addComment(Location begin, Location end, CommentPlacement placement);
963

964
  static String normalizeEOL(Location begin, Location end);
965
  static bool containsNewLine(Location begin, Location end);
966

967
  using Nodes = std::stack<Value*>;
968

969
  Nodes nodes_{};
970
  Errors errors_{};
971
  String document_{};
972
  Location begin_ = nullptr;
973
  Location end_ = nullptr;
974
  Location current_ = nullptr;
975
  Location lastValueEnd_ = nullptr;
976
  Value* lastValue_ = nullptr;
977
  bool lastValueHasAComment_ = false;
978
  String commentsBefore_{};
979

980
  OurFeatures const features_;
981
  bool collectComments_ = false;
982
}; // OurReader
983

984
// complete copy of Read impl, for OurReader
985

986
bool OurReader::containsNewLine(OurReader::Location begin,
185✔
987
                                OurReader::Location end) {
988
  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
225✔
989
}
990

991
OurReader::OurReader(OurFeatures const& features) : features_(features) {}
1,788✔
992

993
bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
926✔
994
                      bool collectComments) {
995
  if (!features_.allowComments_) {
926✔
996
    collectComments = false;
997
  }
998

999
  begin_ = beginDoc;
926✔
1000
  end_ = endDoc;
926✔
1001
  collectComments_ = collectComments;
926✔
1002
  current_ = begin_;
926✔
1003
  lastValueEnd_ = nullptr;
926✔
1004
  lastValue_ = nullptr;
926✔
1005
  commentsBefore_.clear();
1006
  errors_.clear();
926✔
1007
  while (!nodes_.empty())
926✔
1008
    nodes_.pop();
×
1009
  nodes_.push(&root);
926✔
1010

1011
  // skip byte order mark if it exists at the beginning of the UTF-8 text.
1012
  skipBom(features_.skipBom_);
926✔
1013
  bool successful = readValue();
926✔
1014
  nodes_.pop();
919✔
1015
  Token token;
1016
  readTokenSkippingComments(token);
919✔
1017
  if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
919✔
1018
    addError("Extra non-whitespace after JSON value.", token);
5✔
1019
    return false;
5✔
1020
  }
1021
  if (collectComments_ && !commentsBefore_.empty())
914✔
1022
    root.setComment(commentsBefore_, commentAfter);
46✔
1023
  if (features_.strictRoot_) {
914✔
1024
    if (!root.isArray() && !root.isObject()) {
101✔
1025
      // Set error location to start of doc, ideally should be first token found
1026
      // in doc
1027
      token.type_ = tokenError;
4✔
1028
      token.start_ = beginDoc;
4✔
1029
      token.end_ = endDoc;
4✔
1030
      addError(
4✔
1031
          "A valid JSON document must be either an array or an object value.",
1032
          token);
1033
      return false;
4✔
1034
    }
1035
  }
1036
  return successful;
1037
}
1038

1039
bool OurReader::readValue() {
60,295✔
1040
  //  To preserve the old behaviour we cast size_t to int.
1041
  if (nodes_.size() > features_.stackLimit_)
60,295✔
1042
    throwRuntimeError("Exceeded stackLimit in readValue().");
7✔
1043
  Token token;
1044
  readTokenSkippingComments(token);
60,288✔
1045
  bool successful = true;
1046

1047
  if (collectComments_ && !commentsBefore_.empty()) {
60,288✔
1048
    currentValue().setComment(commentsBefore_, commentBefore);
1,203✔
1049
    commentsBefore_.clear();
1050
  }
1051

1052
  switch (token.type_) {
60,288✔
1053
  case tokenObjectBegin:
367✔
1054
    successful = readObject(token);
367✔
1055
    currentValue().setOffsetLimit(current_ - begin_);
366✔
1056
    break;
1057
  case tokenArrayBegin:
6,359✔
1058
    successful = readArray(token);
6,359✔
1059
    currentValue().setOffsetLimit(current_ - begin_);
359✔
1060
    break;
1061
  case tokenNumber:
52,834✔
1062
    successful = decodeNumber(token);
52,834✔
1063
    break;
1064
  case tokenString:
513✔
1065
    successful = decodeString(token);
513✔
1066
    break;
1067
  case tokenTrue: {
48✔
1068
    Value v(true);
48✔
1069
    currentValue().swapPayload(v);
48✔
1070
    currentValue().setOffsetStart(token.start_ - begin_);
48✔
1071
    currentValue().setOffsetLimit(token.end_ - begin_);
48✔
1072
  } break;
48✔
1073
  case tokenFalse: {
31✔
1074
    Value v(false);
31✔
1075
    currentValue().swapPayload(v);
31✔
1076
    currentValue().setOffsetStart(token.start_ - begin_);
31✔
1077
    currentValue().setOffsetLimit(token.end_ - begin_);
31✔
1078
  } break;
31✔
1079
  case tokenNull: {
61✔
1080
    Value v;
61✔
1081
    currentValue().swapPayload(v);
61✔
1082
    currentValue().setOffsetStart(token.start_ - begin_);
61✔
1083
    currentValue().setOffsetLimit(token.end_ - begin_);
61✔
1084
  } break;
61✔
1085
  case tokenNaN: {
1✔
1086
    Value v(std::numeric_limits<double>::quiet_NaN());
1✔
1087
    currentValue().swapPayload(v);
1✔
1088
    currentValue().setOffsetStart(token.start_ - begin_);
1✔
1089
    currentValue().setOffsetLimit(token.end_ - begin_);
1✔
1090
  } break;
1✔
1091
  case tokenPosInf: {
5✔
1092
    Value v(std::numeric_limits<double>::infinity());
5✔
1093
    currentValue().swapPayload(v);
5✔
1094
    currentValue().setOffsetStart(token.start_ - begin_);
5✔
1095
    currentValue().setOffsetLimit(token.end_ - begin_);
5✔
1096
  } break;
5✔
1097
  case tokenNegInf: {
3✔
1098
    Value v(-std::numeric_limits<double>::infinity());
3✔
1099
    currentValue().swapPayload(v);
3✔
1100
    currentValue().setOffsetStart(token.start_ - begin_);
3✔
1101
    currentValue().setOffsetLimit(token.end_ - begin_);
3✔
1102
  } break;
3✔
1103
  case tokenArraySeparator:
41✔
1104
  case tokenObjectEnd:
1105
  case tokenArrayEnd:
1106
    if (features_.allowDroppedNullPlaceholders_) {
41✔
1107
      // "Un-read" the current token and mark the current value as a null
1108
      // token.
1109
      current_--;
29✔
1110
      Value v;
29✔
1111
      currentValue().swapPayload(v);
29✔
1112
      currentValue().setOffsetStart(current_ - begin_ - 1);
29✔
1113
      currentValue().setOffsetLimit(current_ - begin_);
29✔
1114
      break;
1115
    } // else, fall through ...
29✔
1116
  default:
1117
    currentValue().setOffsetStart(token.start_ - begin_);
37✔
1118
    currentValue().setOffsetLimit(token.end_ - begin_);
37✔
1119
    return addError("Syntax error: value, object or array expected.", token);
74✔
1120
  }
1121

1122
  if (collectComments_) {
54,250✔
1123
    lastValueEnd_ = current_;
53,789✔
1124
    lastValueHasAComment_ = false;
53,789✔
1125
    lastValue_ = &currentValue();
53,789✔
1126
  }
1127

1128
  return successful;
1129
}
1130

1131
bool OurReader::readTokenSkippingComments(Token& token) {
115,198✔
1132
  bool success = readToken(token);
115,198✔
1133
  if (features_.allowComments_) {
115,198✔
1134
    while (success && token.type_ == tokenComment) {
114,698✔
1135
      success = readToken(token);
590✔
1136
    }
1137
  }
1138
  return success;
115,198✔
1139
}
1140

1141
bool OurReader::readToken(Token& token) {
116,865✔
1142
  skipSpaces();
116,865✔
1143
  token.start_ = current_;
116,865✔
1144
  Char c = getNextChar();
116,865✔
1145
  bool ok = true;
1146
  switch (c) {
116,865✔
1147
  case '{':
373✔
1148
    token.type_ = tokenObjectBegin;
373✔
1149
    break;
1150
  case '}':
359✔
1151
    token.type_ = tokenObjectEnd;
359✔
1152
    break;
1153
  case '[':
6,359✔
1154
    token.type_ = tokenArrayBegin;
6,359✔
1155
    break;
1156
  case ']':
360✔
1157
    token.type_ = tokenArrayEnd;
360✔
1158
    break;
1159
  case '"':
1,168✔
1160
    token.type_ = tokenString;
1,168✔
1161
    ok = readString();
1,168✔
1162
    break;
1,168✔
1163
  case '\'':
23✔
1164
    if (features_.allowSingleQuotes_) {
23✔
1165
      token.type_ = tokenString;
11✔
1166
      ok = readStringSingleQuote();
11✔
1167
    } else {
1168
      // If we don't allow single quotes, this is a failure case.
1169
      ok = false;
1170
    }
1171
    break;
1172
  case '/':
615✔
1173
    token.type_ = tokenComment;
615✔
1174
    ok = readComment();
615✔
1175
    break;
615✔
1176
  case '0':
52,721✔
1177
  case '1':
1178
  case '2':
1179
  case '3':
1180
  case '4':
1181
  case '5':
1182
  case '6':
1183
  case '7':
1184
  case '8':
1185
  case '9':
1186
    token.type_ = tokenNumber;
52,721✔
1187
    readNumber(false);
52,721✔
1188
    break;
1189
  case '-':
147✔
1190
    if (readNumber(true)) {
147✔
1191
      token.type_ = tokenNumber;
144✔
1192
    } else {
1193
      token.type_ = tokenNegInf;
3✔
1194
      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
3✔
1195
    }
1196
    break;
1197
  case '+':
7✔
1198
    if (readNumber(true)) {
7✔
1199
      token.type_ = tokenNumber;
4✔
1200
    } else {
1201
      token.type_ = tokenPosInf;
3✔
1202
      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
3✔
1203
    }
1204
    break;
1205
  case 't':
72✔
1206
    token.type_ = tokenTrue;
72✔
1207
    ok = match("rue", 3);
72✔
1208
    break;
72✔
1209
  case 'f':
43✔
1210
    token.type_ = tokenFalse;
43✔
1211
    ok = match("alse", 4);
43✔
1212
    break;
43✔
1213
  case 'n':
97✔
1214
    token.type_ = tokenNull;
97✔
1215
    ok = match("ull", 3);
97✔
1216
    break;
97✔
1217
  case 'N':
3✔
1218
    if (features_.allowSpecialFloats_) {
3✔
1219
      token.type_ = tokenNaN;
1✔
1220
      ok = match("aN", 2);
1✔
1221
    } else {
1222
      ok = false;
1223
    }
1224
    break;
1225
  case 'I':
8✔
1226
    if (features_.allowSpecialFloats_) {
8✔
1227
      token.type_ = tokenPosInf;
7✔
1228
      ok = match("nfinity", 7);
7✔
1229
    } else {
1230
      ok = false;
1231
    }
1232
    break;
1233
  case ',':
52,771✔
1234
    token.type_ = tokenArraySeparator;
52,771✔
1235
    break;
1236
  case ':':
663✔
1237
    token.type_ = tokenMemberSeparator;
663✔
1238
    break;
1239
  case 0:
938✔
1240
    token.type_ = tokenEndOfStream;
938✔
1241
    break;
1242
  default:
1243
    ok = false;
1244
    break;
1245
  }
1246
  if (!ok)
2,020✔
1247
    token.type_ = tokenError;
213✔
1248
  token.end_ = current_;
116,865✔
1249
  return ok;
116,865✔
1250
}
1251

1252
void OurReader::skipSpaces() {
175,630✔
1253
  while (current_ != end_) {
295,356✔
1254
    Char c = *current_;
294,418✔
1255
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
294,418✔
1256
      ++current_;
119,726✔
1257
    else
1258
      break;
1259
  }
1260
}
175,630✔
1261

1262
void OurReader::skipBom(bool skipBom) {
926✔
1263
  // The default behavior is to skip BOM.
1264
  if (skipBom) {
926✔
1265
    if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
925✔
1266
      begin_ += 3;
1✔
1267
      current_ = begin_;
1✔
1268
    }
1269
  }
1270
}
926✔
1271

1272
bool OurReader::match(const Char* pattern, int patternLength) {
226✔
1273
  if (end_ - current_ < patternLength)
226✔
1274
    return false;
1275
  int index = patternLength;
1276
  while (index--)
797✔
1277
    if (current_[index] != pattern[index])
631✔
1278
      return false;
1279
  current_ += patternLength;
166✔
1280
  return true;
166✔
1281
}
1282

1283
bool OurReader::readComment() {
615✔
1284
  const Location commentBegin = current_ - 1;
615✔
1285
  const Char c = getNextChar();
615✔
1286
  bool successful = false;
1287
  bool cStyleWithEmbeddedNewline = false;
615✔
1288

1289
  const bool isCStyleComment = (c == '*');
1290
  const bool isCppStyleComment = (c == '/');
1291
  if (isCStyleComment) {
615✔
1292
    successful = readCStyleComment(&cStyleWithEmbeddedNewline);
85✔
1293
  } else if (isCppStyleComment) {
530✔
1294
    successful = readCppStyleComment();
530✔
1295
  }
1296

1297
  if (!successful)
615✔
1298
    return false;
×
1299

1300
  if (collectComments_) {
615✔
1301
    CommentPlacement placement = commentBefore;
1302

1303
    if (!lastValueHasAComment_) {
597✔
1304
      if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
579✔
1305
        if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
65✔
1306
          placement = commentAfterOnSameLine;
1307
          lastValueHasAComment_ = true;
64✔
1308
        }
1309
      }
1310
    }
1311

1312
    addComment(commentBegin, current_, placement);
597✔
1313
  }
1314
  return true;
1315
}
1316

1317
String OurReader::normalizeEOL(OurReader::Location begin,
597✔
1318
                               OurReader::Location end) {
1319
  String normalized;
1320
  normalized.reserve(static_cast<size_t>(end - begin));
597✔
1321
  OurReader::Location current = begin;
1322
  while (current != end) {
21,944✔
1323
    char c = *current++;
21,347✔
1324
    if (c == '\r') {
21,347✔
1325
      if (current != end && *current == '\n')
3✔
1326
        // convert dos EOL
1327
        ++current;
1✔
1328
      // convert Mac EOL
1329
      normalized += '\n';
1330
    } else {
1331
      normalized += c;
21,344✔
1332
    }
1333
  }
1334
  return normalized;
597✔
1335
}
1336

1337
void OurReader::addComment(Location begin, Location end,
597✔
1338
                           CommentPlacement placement) {
1339
  assert(collectComments_);
597✔
1340
  const String& normalized = normalizeEOL(begin, end);
597✔
1341
  if (placement == commentAfterOnSameLine) {
597✔
1342
    assert(lastValue_ != nullptr);
64✔
1343
    lastValue_->setComment(normalized, placement);
128✔
1344
  } else {
1345
    commentsBefore_ += normalized;
533✔
1346
  }
1347
}
597✔
1348

1349
bool OurReader::readCStyleComment(bool* containsNewLineResult) {
85✔
1350
  *containsNewLineResult = false;
85✔
1351

1352
  while ((current_ + 1) < end_) {
2,754✔
1353
    Char c = getNextChar();
2,669✔
1354
    if (c == '*' && *current_ == '/')
2,669✔
1355
      break;
1356
    if (c == '\n')
2,584✔
1357
      *containsNewLineResult = true;
97✔
1358
  }
1359

1360
  return getNextChar() == '/';
85✔
1361
}
1362

1363
bool OurReader::readCppStyleComment() {
530✔
1364
  while (current_ != end_) {
18,083✔
1365
    Char c = getNextChar();
18,077✔
1366
    if (c == '\n')
18,077✔
1367
      break;
1368
    if (c == '\r') {
17,556✔
1369
      // Consume DOS EOL. It will be normalized in addComment.
1370
      if (current_ != end_ && *current_ == '\n')
3✔
1371
        getNextChar();
1✔
1372
      // Break on Moc OS 9 EOL.
1373
      break;
1374
    }
1375
  }
1376
  return true;
530✔
1377
}
1378

1379
bool OurReader::readNumber(bool checkInf) {
52,875✔
1380
  Location p = current_;
52,875✔
1381
  if (checkInf && p != end_ && *p == 'I') {
52,875✔
1382
    current_ = ++p;
6✔
1383
    return false;
6✔
1384
  }
1385
  char c = '0'; // stopgap for already consumed character
1386
  // integral part
1387
  while (c >= '0' && c <= '9')
235,516✔
1388
    c = (current_ = p) < end_ ? *p++ : '\0';
182,647✔
1389
  // fractional part
1390
  if (c == '.') {
52,869✔
1391
    c = (current_ = p) < end_ ? *p++ : '\0';
113✔
1392
    while (c >= '0' && c <= '9')
785✔
1393
      c = (current_ = p) < end_ ? *p++ : '\0';
672✔
1394
  }
1395
  // exponential part
1396
  if (c == 'e' || c == 'E') {
52,869✔
1397
    c = (current_ = p) < end_ ? *p++ : '\0';
103✔
1398
    if (c == '+' || c == '-')
103✔
1399
      c = (current_ = p) < end_ ? *p++ : '\0';
76✔
1400
    while (c >= '0' && c <= '9')
306✔
1401
      c = (current_ = p) < end_ ? *p++ : '\0';
203✔
1402
  }
1403
  return true;
1404
}
1405
bool OurReader::readString() {
1,168✔
1406
  Char c = 0;
1407
  while (current_ != end_) {
34,509✔
1408
    c = getNextChar();
34,509✔
1409
    if (c == '\\')
34,509✔
1410
      getNextChar();
1,275✔
1411
    else if (c == '"')
33,234✔
1412
      break;
1413
  }
1414
  return c == '"';
1,168✔
1415
}
1416

1417
bool OurReader::readStringSingleQuote() {
11✔
1418
  Char c = 0;
1419
  while (current_ != end_) {
26✔
1420
    c = getNextChar();
26✔
1421
    if (c == '\\')
26✔
1422
      getNextChar();
2✔
1423
    else if (c == '\'')
24✔
1424
      break;
1425
  }
1426
  return c == '\'';
11✔
1427
}
1428

1429
bool OurReader::readObject(Token& token) {
367✔
1430
  Token tokenName;
1431
  String name;
1432
  Value init(objectValue);
367✔
1433
  currentValue().swapPayload(init);
367✔
1434
  currentValue().setOffsetStart(token.start_ - begin_);
367✔
1435
  while (readTokenSkippingComments(tokenName)) {
691✔
1436
    if (tokenName.type_ == tokenObjectEnd &&
682✔
1437
        (name.empty() ||
6✔
1438
         features_.allowTrailingCommas_)) // empty object or trailing comma
6✔
1439
      return true;
340✔
1440
    name.clear();
1441
    if (tokenName.type_ == tokenString) {
657✔
1442
      if (!decodeString(tokenName, name))
637✔
1443
        return recoverFromError(tokenObjectEnd);
×
1444
    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
20✔
1445
      Value numberName;
3✔
1446
      if (!decodeNumber(tokenName, numberName))
3✔
1447
        return recoverFromError(tokenObjectEnd);
×
1448
      name = numberName.asString();
3✔
1449
    } else {
3✔
1450
      break;
1451
    }
1452
    if (name.length() >= (1U << 30))
640✔
1453
      throwRuntimeError("keylength >= 2^30");
×
1454
    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
640✔
1455
      String msg = "Duplicate key: '" + name + "'";
1✔
1456
      return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1✔
1457
    }
1458

1459
    Token colon;
1460
    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
639✔
1461
      return addErrorAndRecover("Missing ':' after object member name", colon,
14✔
1462
                                tokenObjectEnd);
1463
    }
1464
    Value& value = currentValue()[name];
632✔
1465
    nodes_.push(&value);
632✔
1466
    bool ok = readValue();
632✔
1467
    nodes_.pop();
631✔
1468
    if (!ok) // error already set
631✔
1469
      return recoverFromError(tokenObjectEnd);
22✔
1470

1471
    Token comma;
1472
    if (!readTokenSkippingComments(comma) ||
609✔
1473
        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
601✔
1474
      return addErrorAndRecover("Missing ',' or '}' in object declaration",
54✔
1475
                                comma, tokenObjectEnd);
1476
    }
1477
    if (comma.type_ == tokenObjectEnd)
582✔
1478
      return true;
1479
  }
1480
  return addErrorAndRecover("Missing '}' or object member name", tokenName,
52✔
1481
                            tokenObjectEnd);
1482
}
367✔
1483

1484
bool OurReader::readArray(Token& token) {
6,359✔
1485
  Value init(arrayValue);
6,359✔
1486
  currentValue().swapPayload(init);
6,359✔
1487
  currentValue().setOffsetStart(token.start_ - begin_);
6,359✔
1488
  int index = 0;
1489
  for (;;) {
1490
    skipSpaces();
58,765✔
1491
    if (current_ != end_ && *current_ == ']' &&
58,765✔
1492
        (index == 0 ||
14✔
1493
         (features_.allowTrailingCommas_ &&
14✔
1494
          !features_.allowDroppedNullPlaceholders_))) // empty array or trailing
14✔
1495
                                                      // comma
1496
    {
1497
      Token endArray;
1498
      readToken(endArray);
28✔
1499
      return true;
1500
    }
1501
    Value& value = currentValue()[index++];
58,737✔
1502
    nodes_.push(&value);
58,737✔
1503
    bool ok = readValue();
58,737✔
1504
    nodes_.pop();
52,737✔
1505
    if (!ok) // error already set
52,737✔
1506
      return recoverFromError(tokenArrayEnd);
46✔
1507

1508
    Token currentToken;
1509
    // Accept Comment after last item in the array.
1510
    ok = readTokenSkippingComments(currentToken);
52,691✔
1511
    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
52,691✔
1512
                         currentToken.type_ != tokenArrayEnd);
52,691✔
1513
    if (!ok || badTokenType) {
52,691✔
1514
      return addErrorAndRecover("Missing ',' or ']' in array declaration",
46✔
1515
                                currentToken, tokenArrayEnd);
1516
    }
1517
    if (currentToken.type_ == tokenArrayEnd)
52,668✔
1518
      break;
1519
  }
52,406✔
1520
  return true;
262✔
1521
}
6,359✔
1522

1523
bool OurReader::decodeNumber(Token& token) {
52,834✔
1524
  Value decoded;
52,834✔
1525
  if (!decodeNumber(token, decoded))
52,834✔
1526
    return false;
1527
  currentValue().swapPayload(decoded);
52,825✔
1528
  currentValue().setOffsetStart(token.start_ - begin_);
52,825✔
1529
  currentValue().setOffsetLimit(token.end_ - begin_);
52,825✔
1530
  return true;
1531
}
52,834✔
1532

1533
bool OurReader::decodeNumber(Token& token, Value& decoded) {
52,837✔
1534
  // Attempts to parse the number as an integer. If the number is
1535
  // larger than the maximum supported value of an integer then
1536
  // we decode the number as a double.
1537
  Location current = token.start_;
52,837✔
1538
  const bool isNegative = *current == '-';
52,837✔
1539
  if (isNegative) {
52,837✔
1540
    ++current;
141✔
1541
  }
1542

1543
  // We assume we can represent the largest and smallest integer types as
1544
  // unsigned integers with separate sign. This is only true if they can fit
1545
  // into an unsigned integer.
1546
  static_assert(Value::maxLargestInt <= Value::maxLargestUInt,
1547
                "Int must be smaller than UInt");
1548

1549
  // We need to convert minLargestInt into a positive number. The easiest way
1550
  // to do this conversion is to assume our "threshold" value of minLargestInt
1551
  // divided by 10 can fit in maxLargestInt when absolute valued. This should
1552
  // be a safe assumption.
1553
  static_assert(Value::minLargestInt <= -Value::maxLargestInt,
1554
                "The absolute value of minLargestInt must be greater than or "
1555
                "equal to maxLargestInt");
1556
  static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,
1557
                "The absolute value of minLargestInt must be only 1 magnitude "
1558
                "larger than maxLargest Int");
1559

1560
  static constexpr Value::LargestUInt positive_threshold =
1561
      Value::maxLargestUInt / 10;
1562
  static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10;
1563

1564
  // For the negative values, we have to be more careful. Since typically
1565
  // -Value::minLargestInt will cause an overflow, we first divide by 10 and
1566
  // then take the inverse. This assumes that minLargestInt is only a single
1567
  // power of 10 different in magnitude, which we check above. For the last
1568
  // digit, we take the modulus before negating for the same reason.
1569
  static constexpr auto negative_threshold =
1570
      Value::LargestUInt(-(Value::minLargestInt / 10));
1571
  static constexpr auto negative_last_digit =
1572
      Value::UInt(-(Value::minLargestInt % 10));
1573

1574
  const Value::LargestUInt threshold =
1575
      isNegative ? negative_threshold : positive_threshold;
52,837✔
1576
  const Value::UInt max_last_digit =
1577
      isNegative ? negative_last_digit : positive_last_digit;
52,837✔
1578

1579
  Value::LargestUInt value = 0;
1580
  while (current < token.end_) {
235,282✔
1581
    Char c = *current++;
182,641✔
1582
    if (c < '0' || c > '9')
182,641✔
1583
      return decodeDouble(token, decoded);
177✔
1584

1585
    const auto digit(static_cast<Value::UInt>(c - '0'));
182,464✔
1586
    if (value >= threshold) {
182,464✔
1587
      // We've hit or exceeded the max value divided by 10 (rounded down). If
1588
      // a) we've only just touched the limit, meaning value == threshold,
1589
      // b) this is the last digit, or
1590
      // c) it's small enough to fit in that rounding delta, we're okay.
1591
      // Otherwise treat this number as a double to avoid overflow.
1592
      if (value > threshold || current != token.end_ ||
43✔
1593
          digit > max_last_digit) {
1594
        return decodeDouble(token, decoded);
19✔
1595
      }
1596
    }
1597
    value = value * 10 + digit;
182,445✔
1598
  }
1599

1600
  if (isNegative) {
52,641✔
1601
    // We use the same magnitude assumption here, just in case.
1602
    const auto last_digit = static_cast<Value::UInt>(value % 10);
89✔
1603
    decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
89✔
1604
  } else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
52,552✔
1605
    decoded = Value::LargestInt(value);
52,528✔
1606
  } else {
1607
    decoded = value;
24✔
1608
  }
1609

1610
  return true;
1611
}
1612

1613
bool OurReader::decodeDouble(Token& token) {
×
1614
  Value decoded;
×
1615
  if (!decodeDouble(token, decoded))
×
1616
    return false;
1617
  currentValue().swapPayload(decoded);
×
1618
  currentValue().setOffsetStart(token.start_ - begin_);
×
1619
  currentValue().setOffsetLimit(token.end_ - begin_);
×
1620
  return true;
1621
}
×
1622

1623
bool OurReader::decodeDouble(Token& token, Value& decoded) {
196✔
1624
  double value = 0;
196✔
1625
  const String buffer(token.start_, token.end_);
196✔
1626
  IStringStream is(buffer);
196✔
1627
  if (!(is >> value)) {
196✔
1628
    if (value == std::numeric_limits<double>::max())
33✔
1629
      value = std::numeric_limits<double>::infinity();
12✔
1630
    else if (value == std::numeric_limits<double>::lowest())
21✔
1631
      value = -std::numeric_limits<double>::infinity();
12✔
1632
    else if (!std::isinf(value))
9✔
1633
      return addError(
9✔
1634
          "'" + String(token.start_, token.end_) + "' is not a number.", token);
27✔
1635
  }
1636
  decoded = value;
187✔
1637
  return true;
187✔
1638
}
196✔
1639

1640
bool OurReader::decodeString(Token& token) {
513✔
1641
  String decoded_string;
1642
  if (!decodeString(token, decoded_string))
513✔
1643
    return false;
1644
  Value decoded(decoded_string);
496✔
1645
  currentValue().swapPayload(decoded);
496✔
1646
  currentValue().setOffsetStart(token.start_ - begin_);
496✔
1647
  currentValue().setOffsetLimit(token.end_ - begin_);
496✔
1648
  return true;
1649
}
496✔
1650

1651
bool OurReader::decodeString(Token& token, String& decoded) {
1,150✔
1652
  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1,150✔
1653
  Location current = token.start_ + 1; // skip '"'
1,150✔
1654
  Location end = token.end_ - 1;       // do not include '"'
1,150✔
1655
  while (current != end) {
33,557✔
1656
    Char c = *current++;
32,424✔
1657
    if (c == '"')
32,424✔
1658
      break;
1659
    if (c == '\\') {
32,424✔
1660
      if (current == end)
1,254✔
1661
        return addError("Empty escape sequence in string", token, current);
×
1662
      Char escape = *current++;
1,254✔
1663
      switch (escape) {
1,254✔
1664
      case '"':
1665
        decoded += '"';
1666
        break;
1667
      case '/':
1668
        decoded += '/';
1669
        break;
1670
      case '\\':
1671
        decoded += '\\';
1672
        break;
1673
      case 'b':
1674
        decoded += '\b';
1675
        break;
1676
      case 'f':
1677
        decoded += '\f';
1678
        break;
1679
      case 'n':
1680
        decoded += '\n';
1681
        break;
1682
      case 'r':
1683
        decoded += '\r';
1684
        break;
1685
      case 't':
1686
        decoded += '\t';
1687
        break;
1688
      case 'u': {
145✔
1689
        unsigned int unicode;
1690
        if (!decodeUnicodeCodePoint(token, current, end, unicode))
145✔
1691
          return false;
4✔
1692
        decoded += codePointToUTF8(unicode);
141✔
1693
      } break;
141✔
1694
      default:
13✔
1695
        return addError("Bad escape sequence in string", token, current);
26✔
1696
      }
1697
    } else {
1698
      decoded += c;
31,170✔
1699
    }
1700
  }
1701
  return true;
1702
}
1703

1704
bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
145✔
1705
                                       Location end, unsigned int& unicode) {
1706

1707
  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
145✔
1708
    return false;
1709
  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
143✔
1710
    // surrogate pairs
1711
    if (end - current < 6)
15✔
1712
      return addError(
2✔
1713
          "additional six characters expected to parse unicode surrogate pair.",
1714
          token, current);
1715
    if (*(current++) == '\\' && *(current++) == 'u') {
14✔
1716
      unsigned int surrogatePair;
1717
      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
13✔
1718
        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
13✔
1719
      } else
1720
        return false;
×
1721
    } else
1722
      return addError("expecting another \\u token to begin the second half of "
2✔
1723
                      "a unicode surrogate pair",
1724
                      token, current);
1725
  }
1726
  return true;
1727
}
1728

1729
bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
158✔
1730
                                            Location end,
1731
                                            unsigned int& ret_unicode) {
1732
  if (end - current < 4)
158✔
1733
    return addError(
2✔
1734
        "Bad unicode escape sequence in string: four digits expected.", token,
1735
        current);
1736
  int unicode = 0;
1737
  for (int index = 0; index < 4; ++index) {
783✔
1738
    Char c = *current++;
627✔
1739
    unicode *= 16;
627✔
1740
    if (c >= '0' && c <= '9')
627✔
1741
      unicode += c - '0';
400✔
1742
    else if (c >= 'a' && c <= 'f')
227✔
1743
      unicode += c - 'a' + 10;
115✔
1744
    else if (c >= 'A' && c <= 'F')
112✔
1745
      unicode += c - 'A' + 10;
111✔
1746
    else
1747
      return addError(
2✔
1748
          "Bad unicode escape sequence in string: hexadecimal digit expected.",
1749
          token, current);
1750
  }
1751
  ret_unicode = static_cast<unsigned int>(unicode);
156✔
1752
  return true;
156✔
1753
}
1754

1755
bool OurReader::addError(const String& message, Token& token, Location extra) {
156✔
1756
  ErrorInfo info;
1757
  info.token_ = token;
156✔
1758
  info.message_ = message;
1759
  info.extra_ = extra;
156✔
1760
  errors_.push_back(info);
156✔
1761
  return false;
156✔
1762
}
1763

1764
bool OurReader::recoverFromError(TokenType skipUntilToken) {
152✔
1765
  size_t errorCount = errors_.size();
1766
  Token skip;
1767
  for (;;) {
1768
    if (!readToken(skip))
410✔
1769
      errors_.resize(errorCount); // discard errors caused by recovery
173✔
1770
    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
410✔
1771
      break;
1772
  }
1773
  errors_.resize(errorCount);
152✔
1774
  return false;
152✔
1775
}
1776

1777
bool OurReader::addErrorAndRecover(const String& message, Token& token,
84✔
1778
                                   TokenType skipUntilToken) {
1779
  addError(message, token);
84✔
1780
  return recoverFromError(skipUntilToken);
84✔
1781
}
1782

1783
Value& OurReader::currentValue() { return *(nodes_.top()); }
288,310✔
1784

1785
OurReader::Char OurReader::getNextChar() {
174,124✔
1786
  if (current_ == end_)
174,124✔
1787
    return 0;
1788
  return *current_++;
173,186✔
1789
}
1790

1791
void OurReader::getLocationLineAndColumn(Location location, int& line,
172✔
1792
                                         int& column) const {
1793
  Location current = begin_;
172✔
1794
  Location lastLineStart = current;
1795
  line = 0;
172✔
1796
  while (current < location && current != end_) {
2,253✔
1797
    Char c = *current++;
2,081✔
1798
    if (c == '\r') {
2,081✔
1799
      if (current != end_ && *current == '\n')
1✔
1800
        ++current;
×
1801
      lastLineStart = current;
1802
      ++line;
1✔
1803
    } else if (c == '\n') {
2,080✔
1804
      lastLineStart = current;
1805
      ++line;
28✔
1806
    }
1807
  }
1808
  // column & line start at 1
1809
  column = int(location - lastLineStart) + 1;
172✔
1810
  ++line;
172✔
1811
}
172✔
1812

1813
String OurReader::getLocationLineAndColumn(Location location) const {
172✔
1814
  int line, column;
1815
  getLocationLineAndColumn(location, line, column);
172✔
1816
  char buffer[18 + 16 + 16 + 1];
1817
  jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
172✔
1818
  return buffer;
172✔
1819
}
1820

1821
String OurReader::getFormattedErrorMessages() const {
917✔
1822
  String formattedMessage;
1823
  for (const auto& error : errors_) {
1,072✔
1824
    formattedMessage +=
1825
        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
310✔
1826
    formattedMessage += "  " + error.message_ + "\n";
310✔
1827
    if (error.extra_)
155✔
1828
      formattedMessage +=
1829
          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
34✔
1830
  }
1831
  return formattedMessage;
917✔
1832
}
1833

1834
std::vector<CharReader::StructuredError>
1835
OurReader::getStructuredErrors() const {
2✔
1836
  std::vector<CharReader::StructuredError> allErrors;
1837
  for (const auto& error : errors_) {
3✔
1838
    CharReader::StructuredError structured;
1839
    structured.offset_start = error.token_.start_ - begin_;
1✔
1840
    structured.offset_limit = error.token_.end_ - begin_;
1✔
1841
    structured.message = error.message_;
1✔
1842
    allErrors.push_back(structured);
1✔
1843
  }
1844
  return allErrors;
2✔
1845
}
×
1846

1847
class OurCharReader : public CharReader {
1848

1849
public:
1850
  OurCharReader(bool collectComments, OurFeatures const& features)
894✔
1851
      : CharReader(
894✔
1852
            std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}
1,788✔
1853

1854
protected:
1855
  class OurImpl : public Impl {
1856
  public:
1857
    OurImpl(bool collectComments, OurFeatures const& features)
1858
        : collectComments_(collectComments), reader_(features) {}
894✔
1859

1860
    bool parse(char const* beginDoc, char const* endDoc, Value* root,
926✔
1861
               String* errs) override {
1862
      bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
926✔
1863
      if (errs) {
919✔
1864
        *errs = reader_.getFormattedErrorMessages();
1,834✔
1865
      }
1866
      return ok;
919✔
1867
    }
1868

1869
    std::vector<CharReader::StructuredError>
1870
    getStructuredErrors() const override {
2✔
1871
      return reader_.getStructuredErrors();
2✔
1872
    }
1873

1874
  private:
1875
    bool const collectComments_;
1876
    OurReader reader_;
1877
  };
1878
};
1879

1880
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
891✔
1881
CharReaderBuilder::~CharReaderBuilder() = default;
1,782✔
1882
CharReader* CharReaderBuilder::newCharReader() const {
894✔
1883
  bool collectComments = settings_["collectComments"].asBool();
894✔
1884
  OurFeatures features = OurFeatures::all();
894✔
1885
  features.allowComments_ = settings_["allowComments"].asBool();
894✔
1886
  features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
894✔
1887
  features.strictRoot_ = settings_["strictRoot"].asBool();
894✔
1888
  features.allowDroppedNullPlaceholders_ =
894✔
1889
      settings_["allowDroppedNullPlaceholders"].asBool();
894✔
1890
  features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
894✔
1891
  features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
894✔
1892

1893
  // Stack limit is always a size_t, so we get this as an unsigned int
1894
  // regardless of it we have 64-bit integer support enabled.
1895
  features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());
894✔
1896
  features.failIfExtra_ = settings_["failIfExtra"].asBool();
894✔
1897
  features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
894✔
1898
  features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
894✔
1899
  features.skipBom_ = settings_["skipBom"].asBool();
894✔
1900
  return new OurCharReader(collectComments, features);
894✔
1901
}
1902

1903
bool CharReaderBuilder::validate(Json::Value* invalid) const {
2✔
1904
  static const auto& valid_keys = *new std::set<String>{
1905
      "collectComments",
1906
      "allowComments",
1907
      "allowTrailingCommas",
1908
      "strictRoot",
1909
      "allowDroppedNullPlaceholders",
1910
      "allowNumericKeys",
1911
      "allowSingleQuotes",
1912
      "stackLimit",
1913
      "failIfExtra",
1914
      "rejectDupKeys",
1915
      "allowSpecialFloats",
1916
      "skipBom",
1917
  };
14✔
1918
  for (auto si = settings_.begin(); si != settings_.end(); ++si) {
54✔
1919
    auto key = si.name();
25✔
1920
    if (valid_keys.count(key))
25✔
1921
      continue;
1922
    if (invalid)
1✔
1923
      (*invalid)[key] = *si;
1✔
1924
    else
1925
      return false;
1926
  }
1927
  return invalid ? invalid->empty() : true;
2✔
1928
}
1929

1930
Value& CharReaderBuilder::operator[](const String& key) {
1✔
1931
  return settings_[key];
1✔
1932
}
1933
// static
1934
void CharReaderBuilder::strictMode(Json::Value* settings) {
3✔
1935
  //! [CharReaderBuilderStrictMode]
1936
  (*settings)["allowComments"] = false;
3✔
1937
  (*settings)["allowTrailingCommas"] = false;
3✔
1938
  (*settings)["strictRoot"] = true;
3✔
1939
  (*settings)["allowDroppedNullPlaceholders"] = false;
3✔
1940
  (*settings)["allowNumericKeys"] = false;
3✔
1941
  (*settings)["allowSingleQuotes"] = false;
3✔
1942
  (*settings)["stackLimit"] = 1000;
3✔
1943
  (*settings)["failIfExtra"] = true;
3✔
1944
  (*settings)["rejectDupKeys"] = true;
3✔
1945
  (*settings)["allowSpecialFloats"] = false;
3✔
1946
  (*settings)["skipBom"] = true;
3✔
1947
  //! [CharReaderBuilderStrictMode]
1948
}
3✔
1949
// static
1950
void CharReaderBuilder::setDefaults(Json::Value* settings) {
891✔
1951
  //! [CharReaderBuilderDefaults]
1952
  (*settings)["collectComments"] = true;
891✔
1953
  (*settings)["allowComments"] = true;
891✔
1954
  (*settings)["allowTrailingCommas"] = true;
891✔
1955
  (*settings)["strictRoot"] = false;
891✔
1956
  (*settings)["allowDroppedNullPlaceholders"] = false;
891✔
1957
  (*settings)["allowNumericKeys"] = false;
891✔
1958
  (*settings)["allowSingleQuotes"] = false;
891✔
1959
  (*settings)["stackLimit"] = 1000;
891✔
1960
  (*settings)["failIfExtra"] = false;
891✔
1961
  (*settings)["rejectDupKeys"] = false;
891✔
1962
  (*settings)["allowSpecialFloats"] = false;
891✔
1963
  (*settings)["skipBom"] = true;
891✔
1964
  //! [CharReaderBuilderDefaults]
1965
}
891✔
1966

1967
std::vector<CharReader::StructuredError>
1968
CharReader::getStructuredErrors() const {
2✔
1969
  return _impl->getStructuredErrors();
2✔
1970
}
1971

1972
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,
926✔
1973
                       String* errs) {
1974
  return _impl->parse(beginDoc, endDoc, root, errs);
926✔
1975
}
1976

1977
//////////////////////////////////
1978
// global functions
1979

1980
bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
4✔
1981
                     String* errs) {
1982
  OStringStream ssin;
4✔
1983
  ssin << sin.rdbuf();
4✔
1984
  String doc = ssin.str();
1985
  char const* begin = doc.data();
1986
  char const* end = begin + doc.size();
4✔
1987
  // Note that we do not actually need a null-terminator.
1988
  CharReaderPtr const reader(fact.newCharReader());
4✔
1989
  return reader->parse(begin, end, root, errs);
8✔
1990
}
4✔
1991

1992
IStream& operator>>(IStream& sin, Value& root) {
1✔
1993
  CharReaderBuilder b;
1✔
1994
  String errs;
1995
  bool ok = parseFromStream(b, sin, &root, &errs);
1✔
1996
  if (!ok) {
1✔
1997
    throwRuntimeError(errs);
×
1998
  }
1999
  return sin;
1✔
2000
}
1✔
2001

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

© 2025 Coveralls, Inc