Coverage Report

Created: 2026-02-14 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jsoncpp/src/lib_json/json_reader.cpp
Line
Count
Source
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 <iterator>
20
#include <limits>
21
#include <memory>
22
#include <set>
23
#include <sstream>
24
#include <utility>
25
26
#include <cstdio>
27
28
#if defined(_MSC_VER)
29
#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
30
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
31
#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
32
#endif //_MSC_VER
33
34
#if defined(_MSC_VER)
35
// Disable warning about strdup being deprecated.
36
#pragma warning(disable : 4996)
37
#endif
38
39
// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
40
// time to change the stack limit
41
#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
42
#define JSONCPP_DEPRECATED_STACK_LIMIT 1000
43
#endif
44
45
static size_t const stackLimit_g =
46
    JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
47
48
namespace Json {
49
50
using CharReaderPtr = std::unique_ptr<CharReader>;
51
52
// Implementation of class Features
53
// ////////////////////////////////
54
55
0
Features::Features() = default;
56
57
0
Features Features::all() { return {}; }
58
59
0
Features Features::strictMode() {
60
0
  Features features;
61
0
  features.allowComments_ = false;
62
0
  features.strictRoot_ = true;
63
0
  features.allowDroppedNullPlaceholders_ = false;
64
0
  features.allowNumericKeys_ = false;
65
0
  return features;
66
0
}
67
68
// Implementation of class Reader
69
// ////////////////////////////////
70
71
0
bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
72
0
  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
73
0
}
74
75
// Class Reader
76
// //////////////////////////////////////////////////////////////////
77
78
0
Reader::Reader() : features_(Features::all()) {}
79
80
0
Reader::Reader(const Features& features) : features_(features) {}
81
82
bool Reader::parse(const std::string& document, Value& root,
83
0
                   bool collectComments) {
84
0
  document_.assign(document.begin(), document.end());
85
0
  const char* begin = document_.c_str();
86
0
  const char* end = begin + document_.length();
87
0
  return parse(begin, end, root, collectComments);
88
0
}
89
90
0
bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
91
  // std::istream_iterator<char> begin(is);
92
  // std::istream_iterator<char> end;
93
  // Those would allow streamed input from a file, if parse() were a
94
  // template function.
95
96
  // Since String is reference-counted, this at least does not
97
  // create an extra copy.
98
0
  String doc(std::istreambuf_iterator<char>(is), {});
99
0
  return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
100
0
}
101
102
bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
103
0
                   bool collectComments) {
104
0
  if (!features_.allowComments_) {
105
0
    collectComments = false;
106
0
  }
107
108
0
  begin_ = beginDoc;
109
0
  end_ = endDoc;
110
0
  collectComments_ = collectComments;
111
0
  current_ = begin_;
112
0
  lastValueEnd_ = nullptr;
113
0
  lastValue_ = nullptr;
114
0
  commentsBefore_.clear();
115
0
  errors_.clear();
116
0
  while (!nodes_.empty())
117
0
    nodes_.pop();
118
0
  nodes_.push(&root);
119
120
0
  bool successful = readValue();
121
0
  Token token;
122
0
  readTokenSkippingComments(token);
123
0
  if (collectComments_ && !commentsBefore_.empty())
124
0
    root.setComment(commentsBefore_, commentAfter);
125
0
  if (features_.strictRoot_) {
126
0
    if (!root.isArray() && !root.isObject()) {
127
      // Set error location to start of doc, ideally should be first token found
128
      // in doc
129
0
      token.type_ = tokenError;
130
0
      token.start_ = beginDoc;
131
0
      token.end_ = endDoc;
132
0
      addError(
133
0
          "A valid JSON document must be either an array or an object value.",
134
0
          token);
135
0
      return false;
136
0
    }
137
0
  }
138
0
  return successful;
139
0
}
140
141
0
bool Reader::readValue() {
142
  // readValue() may call itself only if it calls readObject() or ReadArray().
143
  // These methods execute nodes_.push() just before and nodes_.pop)() just
144
  // after calling readValue(). parse() executes one nodes_.push(), so > instead
145
  // of >=.
146
0
  if (nodes_.size() > stackLimit_g)
147
0
#if JSON_USE_EXCEPTION
148
0
    throwRuntimeError("Exceeded stackLimit in readValue().");
149
#else
150
    // throwRuntimeError aborts. Don't abort here.
151
    return false;
152
#endif
153
154
0
  Token token;
155
0
  readTokenSkippingComments(token);
156
0
  bool successful = true;
157
158
0
  if (collectComments_ && !commentsBefore_.empty()) {
159
0
    currentValue().setComment(commentsBefore_, commentBefore);
160
0
    commentsBefore_.clear();
161
0
  }
162
163
0
  switch (token.type_) {
164
0
  case tokenObjectBegin:
165
0
    successful = readObject(token);
166
0
    currentValue().setOffsetLimit(current_ - begin_);
167
0
    break;
168
0
  case tokenArrayBegin:
169
0
    successful = readArray(token);
170
0
    currentValue().setOffsetLimit(current_ - begin_);
171
0
    break;
172
0
  case tokenNumber:
173
0
    successful = decodeNumber(token);
174
0
    break;
175
0
  case tokenString:
176
0
    successful = decodeString(token);
177
0
    break;
178
0
  case tokenTrue: {
179
0
    Value v(true);
180
0
    currentValue().swapPayload(v);
181
0
    currentValue().setOffsetStart(token.start_ - begin_);
182
0
    currentValue().setOffsetLimit(token.end_ - begin_);
183
0
  } break;
184
0
  case tokenFalse: {
185
0
    Value v(false);
186
0
    currentValue().swapPayload(v);
187
0
    currentValue().setOffsetStart(token.start_ - begin_);
188
0
    currentValue().setOffsetLimit(token.end_ - begin_);
189
0
  } break;
190
0
  case tokenNull: {
191
0
    Value v;
192
0
    currentValue().swapPayload(v);
193
0
    currentValue().setOffsetStart(token.start_ - begin_);
194
0
    currentValue().setOffsetLimit(token.end_ - begin_);
195
0
  } break;
196
0
  case tokenArraySeparator:
197
0
  case tokenObjectEnd:
198
0
  case tokenArrayEnd:
199
0
    if (features_.allowDroppedNullPlaceholders_) {
200
      // "Un-read" the current token and mark the current value as a null
201
      // token.
202
0
      current_--;
203
0
      Value v;
204
0
      currentValue().swapPayload(v);
205
0
      currentValue().setOffsetStart(current_ - begin_ - 1);
206
0
      currentValue().setOffsetLimit(current_ - begin_);
207
0
      break;
208
0
    } // Else, fall through...
209
0
  default:
210
0
    currentValue().setOffsetStart(token.start_ - begin_);
211
0
    currentValue().setOffsetLimit(token.end_ - begin_);
212
0
    return addError("Syntax error: value, object or array expected.", token);
213
0
  }
214
215
0
  if (collectComments_) {
216
0
    lastValueEnd_ = current_;
217
0
    lastValue_ = &currentValue();
218
0
  }
219
220
0
  return successful;
221
0
}
222
223
0
bool Reader::readTokenSkippingComments(Token& token) {
224
0
  bool success = readToken(token);
225
0
  if (features_.allowComments_) {
226
0
    while (success && token.type_ == tokenComment) {
227
0
      success = readToken(token);
228
0
    }
229
0
  }
230
0
  return success;
231
0
}
232
233
0
bool Reader::readToken(Token& token) {
234
0
  skipSpaces();
235
0
  token.start_ = current_;
236
0
  Char c = getNextChar();
237
0
  bool ok = true;
238
0
  switch (c) {
239
0
  case '{':
240
0
    token.type_ = tokenObjectBegin;
241
0
    break;
242
0
  case '}':
243
0
    token.type_ = tokenObjectEnd;
244
0
    break;
245
0
  case '[':
246
0
    token.type_ = tokenArrayBegin;
247
0
    break;
248
0
  case ']':
249
0
    token.type_ = tokenArrayEnd;
250
0
    break;
251
0
  case '"':
252
0
    token.type_ = tokenString;
253
0
    ok = readString();
254
0
    break;
255
0
  case '/':
256
0
    token.type_ = tokenComment;
257
0
    ok = readComment();
258
0
    break;
259
0
  case '0':
260
0
  case '1':
261
0
  case '2':
262
0
  case '3':
263
0
  case '4':
264
0
  case '5':
265
0
  case '6':
266
0
  case '7':
267
0
  case '8':
268
0
  case '9':
269
0
  case '-':
270
0
    token.type_ = tokenNumber;
271
0
    readNumber();
272
0
    break;
273
0
  case 't':
274
0
    token.type_ = tokenTrue;
275
0
    ok = match("rue", 3);
276
0
    break;
277
0
  case 'f':
278
0
    token.type_ = tokenFalse;
279
0
    ok = match("alse", 4);
280
0
    break;
281
0
  case 'n':
282
0
    token.type_ = tokenNull;
283
0
    ok = match("ull", 3);
284
0
    break;
285
0
  case ',':
286
0
    token.type_ = tokenArraySeparator;
287
0
    break;
288
0
  case ':':
289
0
    token.type_ = tokenMemberSeparator;
290
0
    break;
291
0
  case 0:
292
0
    token.type_ = tokenEndOfStream;
293
0
    break;
294
0
  default:
295
0
    ok = false;
296
0
    break;
297
0
  }
298
0
  if (!ok)
299
0
    token.type_ = tokenError;
300
0
  token.end_ = current_;
301
0
  return ok;
302
0
}
303
304
0
void Reader::skipSpaces() {
305
0
  while (current_ != end_) {
306
0
    Char c = *current_;
307
0
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
308
0
      ++current_;
309
0
    else
310
0
      break;
311
0
  }
312
0
}
313
314
0
bool Reader::match(const Char* pattern, int patternLength) {
315
0
  if (end_ - current_ < patternLength)
316
0
    return false;
317
0
  int index = patternLength;
318
0
  while (index--)
319
0
    if (current_[index] != pattern[index])
320
0
      return false;
321
0
  current_ += patternLength;
322
0
  return true;
323
0
}
324
325
0
bool Reader::readComment() {
326
0
  Location commentBegin = current_ - 1;
327
0
  Char c = getNextChar();
328
0
  bool successful = false;
329
0
  if (c == '*')
330
0
    successful = readCStyleComment();
331
0
  else if (c == '/')
332
0
    successful = readCppStyleComment();
333
0
  if (!successful)
334
0
    return false;
335
336
0
  if (collectComments_) {
337
0
    CommentPlacement placement = commentBefore;
338
0
    if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
339
0
      if (c != '*' || !containsNewLine(commentBegin, current_))
340
0
        placement = commentAfterOnSameLine;
341
0
    }
342
343
0
    addComment(commentBegin, current_, placement);
344
0
  }
345
0
  return true;
346
0
}
347
348
0
String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
349
0
  String normalized;
350
0
  normalized.reserve(static_cast<size_t>(end - begin));
351
0
  Reader::Location current = begin;
352
0
  while (current != end) {
353
0
    char c = *current++;
354
0
    if (c == '\r') {
355
0
      if (current != end && *current == '\n')
356
        // convert dos EOL
357
0
        ++current;
358
      // convert Mac EOL
359
0
      normalized += '\n';
360
0
    } else {
361
0
      normalized += c;
362
0
    }
363
0
  }
364
0
  return normalized;
365
0
}
366
367
void Reader::addComment(Location begin, Location end,
368
0
                        CommentPlacement placement) {
369
0
  assert(collectComments_);
370
0
  const String& normalized = normalizeEOL(begin, end);
371
0
  if (placement == commentAfterOnSameLine) {
372
0
    assert(lastValue_ != nullptr);
373
0
    lastValue_->setComment(normalized, placement);
374
0
  } else {
375
0
    commentsBefore_ += normalized;
376
0
  }
377
0
}
378
379
0
bool Reader::readCStyleComment() {
380
0
  while ((current_ + 1) < end_) {
381
0
    Char c = getNextChar();
382
0
    if (c == '*' && *current_ == '/')
383
0
      break;
384
0
  }
385
0
  return getNextChar() == '/';
386
0
}
387
388
0
bool Reader::readCppStyleComment() {
389
0
  while (current_ != end_) {
390
0
    Char c = getNextChar();
391
0
    if (c == '\n')
392
0
      break;
393
0
    if (c == '\r') {
394
      // Consume DOS EOL. It will be normalized in addComment.
395
0
      if (current_ != end_ && *current_ == '\n')
396
0
        getNextChar();
397
      // Break on Moc OS 9 EOL.
398
0
      break;
399
0
    }
400
0
  }
401
0
  return true;
402
0
}
403
404
0
void Reader::readNumber() {
405
0
  Location p = current_;
406
0
  char c = '0'; // stopgap for already consumed character
407
  // integral part
408
0
  while (c >= '0' && c <= '9')
409
0
    c = (current_ = p) < end_ ? *p++ : '\0';
410
  // fractional part
411
0
  if (c == '.') {
412
0
    c = (current_ = p) < end_ ? *p++ : '\0';
413
0
    while (c >= '0' && c <= '9')
414
0
      c = (current_ = p) < end_ ? *p++ : '\0';
415
0
  }
416
  // exponential part
417
0
  if (c == 'e' || c == 'E') {
418
0
    c = (current_ = p) < end_ ? *p++ : '\0';
419
0
    if (c == '+' || c == '-')
420
0
      c = (current_ = p) < end_ ? *p++ : '\0';
421
0
    while (c >= '0' && c <= '9')
422
0
      c = (current_ = p) < end_ ? *p++ : '\0';
423
0
  }
424
0
}
425
426
0
bool Reader::readString() {
427
0
  Char c = '\0';
428
0
  while (current_ != end_) {
429
0
    c = getNextChar();
430
0
    if (c == '\\')
431
0
      getNextChar();
432
0
    else if (c == '"')
433
0
      break;
434
0
  }
435
0
  return c == '"';
436
0
}
437
438
0
bool Reader::readObject(Token& token) {
439
0
  Token tokenName;
440
0
  String name;
441
0
  Value init(objectValue);
442
0
  currentValue().swapPayload(init);
443
0
  currentValue().setOffsetStart(token.start_ - begin_);
444
0
  while (readTokenSkippingComments(tokenName)) {
445
0
    if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
446
0
      return true;
447
0
    name.clear();
448
0
    if (tokenName.type_ == tokenString) {
449
0
      if (!decodeString(tokenName, name))
450
0
        return recoverFromError(tokenObjectEnd);
451
0
    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
452
0
      Value numberName;
453
0
      if (!decodeNumber(tokenName, numberName))
454
0
        return recoverFromError(tokenObjectEnd);
455
0
      name = numberName.asString();
456
0
    } else {
457
0
      break;
458
0
    }
459
460
0
    Token colon;
461
0
    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
462
0
      return addErrorAndRecover("Missing ':' after object member name", colon,
463
0
                                tokenObjectEnd);
464
0
    }
465
0
    Value& value = currentValue()[name];
466
0
    nodes_.push(&value);
467
0
    bool ok = readValue();
468
0
    nodes_.pop();
469
0
    if (!ok) // error already set
470
0
      return recoverFromError(tokenObjectEnd);
471
472
0
    Token comma;
473
0
    if (!readTokenSkippingComments(comma) ||
474
0
        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
475
0
      return addErrorAndRecover("Missing ',' or '}' in object declaration",
476
0
                                comma, tokenObjectEnd);
477
0
    }
478
0
    if (comma.type_ == tokenObjectEnd)
479
0
      return true;
480
0
  }
481
0
  return addErrorAndRecover("Missing '}' or object member name", tokenName,
482
0
                            tokenObjectEnd);
483
0
}
484
485
0
bool Reader::readArray(Token& token) {
486
0
  Value init(arrayValue);
487
0
  currentValue().swapPayload(init);
488
0
  currentValue().setOffsetStart(token.start_ - begin_);
489
0
  skipSpaces();
490
0
  if (current_ != end_ && *current_ == ']') // empty array
491
0
  {
492
0
    Token endArray;
493
0
    readToken(endArray);
494
0
    return true;
495
0
  }
496
0
  int index = 0;
497
0
  for (;;) {
498
0
    Value& value = currentValue()[index++];
499
0
    nodes_.push(&value);
500
0
    bool ok = readValue();
501
0
    nodes_.pop();
502
0
    if (!ok) // error already set
503
0
      return recoverFromError(tokenArrayEnd);
504
505
0
    Token currentToken;
506
    // Accept Comment after last item in the array.
507
0
    ok = readTokenSkippingComments(currentToken);
508
0
    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
509
0
                         currentToken.type_ != tokenArrayEnd);
510
0
    if (!ok || badTokenType) {
511
0
      return addErrorAndRecover("Missing ',' or ']' in array declaration",
512
0
                                currentToken, tokenArrayEnd);
513
0
    }
514
0
    if (currentToken.type_ == tokenArrayEnd)
515
0
      break;
516
0
  }
517
0
  return true;
518
0
}
519
520
0
bool Reader::decodeNumber(Token& token) {
521
0
  Value decoded;
522
0
  if (!decodeNumber(token, decoded))
523
0
    return false;
524
0
  currentValue().swapPayload(decoded);
525
0
  currentValue().setOffsetStart(token.start_ - begin_);
526
0
  currentValue().setOffsetLimit(token.end_ - begin_);
527
0
  return true;
528
0
}
529
530
0
bool Reader::decodeNumber(Token& token, Value& decoded) {
531
  // Attempts to parse the number as an integer. If the number is
532
  // larger than the maximum supported value of an integer then
533
  // we decode the number as a double.
534
0
  Location current = token.start_;
535
0
  bool isNegative = *current == '-';
536
0
  if (isNegative)
537
0
    ++current;
538
  // TODO: Help the compiler do the div and mod at compile time or get rid of
539
  // them.
540
0
  Value::LargestUInt maxIntegerValue =
541
0
      isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
542
0
                 : Value::maxLargestUInt;
543
0
  Value::LargestUInt threshold = maxIntegerValue / 10;
544
0
  Value::LargestUInt value = 0;
545
0
  while (current < token.end_) {
546
0
    Char c = *current++;
547
0
    if (c < '0' || c > '9')
548
0
      return decodeDouble(token, decoded);
549
0
    auto digit(static_cast<Value::UInt>(c - '0'));
550
0
    if (value >= threshold) {
551
      // We've hit or exceeded the max value divided by 10 (rounded down). If
552
      // a) we've only just touched the limit, b) this is the last digit, and
553
      // c) it's small enough to fit in that rounding delta, we're okay.
554
      // Otherwise treat this number as a double to avoid overflow.
555
0
      if (value > threshold || current != token.end_ ||
556
0
          digit > maxIntegerValue % 10) {
557
0
        return decodeDouble(token, decoded);
558
0
      }
559
0
    }
560
0
    value = value * 10 + digit;
561
0
  }
562
0
  if (isNegative && value == maxIntegerValue)
563
0
    decoded = Value::minLargestInt;
564
0
  else if (isNegative)
565
0
    decoded = -Value::LargestInt(value);
566
0
  else if (value <= Value::LargestUInt(Value::maxInt))
567
0
    decoded = Value::LargestInt(value);
568
0
  else
569
0
    decoded = value;
570
0
  return true;
571
0
}
572
573
0
bool Reader::decodeDouble(Token& token) {
574
0
  Value decoded;
575
0
  if (!decodeDouble(token, decoded))
576
0
    return false;
577
0
  currentValue().swapPayload(decoded);
578
0
  currentValue().setOffsetStart(token.start_ - begin_);
579
0
  currentValue().setOffsetLimit(token.end_ - begin_);
580
0
  return true;
581
0
}
582
583
0
bool Reader::decodeDouble(Token& token, Value& decoded) {
584
0
  double value = 0;
585
0
  IStringStream is(String(token.start_, token.end_));
586
0
  if (!(is >> value)) {
587
0
    if (value == std::numeric_limits<double>::max())
588
0
      value = std::numeric_limits<double>::infinity();
589
0
    else if (value == std::numeric_limits<double>::lowest())
590
0
      value = -std::numeric_limits<double>::infinity();
591
0
    else if (!std::isinf(value))
592
0
      return addError(
593
0
          "'" + String(token.start_, token.end_) + "' is not a number.", token);
594
0
  }
595
0
  decoded = value;
596
0
  return true;
597
0
}
598
599
0
bool Reader::decodeString(Token& token) {
600
0
  String decoded_string;
601
0
  if (!decodeString(token, decoded_string))
602
0
    return false;
603
0
  Value decoded(decoded_string);
604
0
  currentValue().swapPayload(decoded);
605
0
  currentValue().setOffsetStart(token.start_ - begin_);
606
0
  currentValue().setOffsetLimit(token.end_ - begin_);
607
0
  return true;
608
0
}
609
610
0
bool Reader::decodeString(Token& token, String& decoded) {
611
0
  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
612
0
  Location current = token.start_ + 1; // skip '"'
613
0
  Location end = token.end_ - 1;       // do not include '"'
614
0
  while (current != end) {
615
0
    Char c = *current++;
616
0
    if (c == '"')
617
0
      break;
618
0
    if (c == '\\') {
619
0
      if (current == end)
620
0
        return addError("Empty escape sequence in string", token, current);
621
0
      Char escape = *current++;
622
0
      switch (escape) {
623
0
      case '"':
624
0
        decoded += '"';
625
0
        break;
626
0
      case '/':
627
0
        decoded += '/';
628
0
        break;
629
0
      case '\\':
630
0
        decoded += '\\';
631
0
        break;
632
0
      case 'b':
633
0
        decoded += '\b';
634
0
        break;
635
0
      case 'f':
636
0
        decoded += '\f';
637
0
        break;
638
0
      case 'n':
639
0
        decoded += '\n';
640
0
        break;
641
0
      case 'r':
642
0
        decoded += '\r';
643
0
        break;
644
0
      case 't':
645
0
        decoded += '\t';
646
0
        break;
647
0
      case 'u': {
648
0
        unsigned int unicode;
649
0
        if (!decodeUnicodeCodePoint(token, current, end, unicode))
650
0
          return false;
651
0
        decoded += codePointToUTF8(unicode);
652
0
      } break;
653
0
      default:
654
0
        return addError("Bad escape sequence in string", token, current);
655
0
      }
656
0
    } else {
657
0
      decoded += c;
658
0
    }
659
0
  }
660
0
  return true;
661
0
}
662
663
bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
664
0
                                    Location end, unsigned int& unicode) {
665
666
0
  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
667
0
    return false;
668
0
  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
669
    // surrogate pairs
670
0
    if (end - current < 6)
671
0
      return addError(
672
0
          "additional six characters expected to parse unicode surrogate pair.",
673
0
          token, current);
674
0
    if (*(current++) == '\\' && *(current++) == 'u') {
675
0
      unsigned int surrogatePair;
676
0
      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
677
0
        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
678
0
      } else
679
0
        return false;
680
0
    } else
681
0
      return addError("expecting another \\u token to begin the second half of "
682
0
                      "a unicode surrogate pair",
683
0
                      token, current);
684
0
  }
685
0
  return true;
686
0
}
687
688
bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
689
                                         Location end,
690
0
                                         unsigned int& ret_unicode) {
691
0
  if (end - current < 4)
692
0
    return addError(
693
0
        "Bad unicode escape sequence in string: four digits expected.", token,
694
0
        current);
695
0
  int unicode = 0;
696
0
  for (int index = 0; index < 4; ++index) {
697
0
    Char c = *current++;
698
0
    unicode *= 16;
699
0
    if (c >= '0' && c <= '9')
700
0
      unicode += c - '0';
701
0
    else if (c >= 'a' && c <= 'f')
702
0
      unicode += c - 'a' + 10;
703
0
    else if (c >= 'A' && c <= 'F')
704
0
      unicode += c - 'A' + 10;
705
0
    else
706
0
      return addError(
707
0
          "Bad unicode escape sequence in string: hexadecimal digit expected.",
708
0
          token, current);
709
0
  }
710
0
  ret_unicode = static_cast<unsigned int>(unicode);
711
0
  return true;
712
0
}
713
714
0
bool Reader::addError(const String& message, Token& token, Location extra) {
715
0
  ErrorInfo info;
716
0
  info.token_ = token;
717
0
  info.message_ = message;
718
0
  info.extra_ = extra;
719
0
  errors_.push_back(info);
720
0
  return false;
721
0
}
722
723
0
bool Reader::recoverFromError(TokenType skipUntilToken) {
724
0
  size_t const errorCount = errors_.size();
725
0
  Token skip;
726
0
  for (;;) {
727
0
    if (!readToken(skip))
728
0
      errors_.resize(errorCount); // discard errors caused by recovery
729
0
    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
730
0
      break;
731
0
  }
732
0
  errors_.resize(errorCount);
733
0
  return false;
734
0
}
735
736
bool Reader::addErrorAndRecover(const String& message, Token& token,
737
0
                                TokenType skipUntilToken) {
738
0
  addError(message, token);
739
0
  return recoverFromError(skipUntilToken);
740
0
}
741
742
0
Value& Reader::currentValue() { return *(nodes_.top()); }
743
744
0
Reader::Char Reader::getNextChar() {
745
0
  if (current_ == end_)
746
0
    return 0;
747
0
  return *current_++;
748
0
}
749
750
void Reader::getLocationLineAndColumn(Location location, int& line,
751
0
                                      int& column) const {
752
0
  Location current = begin_;
753
0
  Location lastLineStart = current;
754
0
  line = 0;
755
0
  while (current < location && current != end_) {
756
0
    Char c = *current++;
757
0
    if (c == '\r') {
758
0
      if (current != end_ && *current == '\n')
759
0
        ++current;
760
0
      lastLineStart = current;
761
0
      ++line;
762
0
    } else if (c == '\n') {
763
0
      lastLineStart = current;
764
0
      ++line;
765
0
    }
766
0
  }
767
  // column & line start at 1
768
0
  column = int(location - lastLineStart) + 1;
769
0
  ++line;
770
0
}
771
772
0
String Reader::getLocationLineAndColumn(Location location) const {
773
0
  int line, column;
774
0
  getLocationLineAndColumn(location, line, column);
775
0
  char buffer[18 + 16 + 16 + 1];
776
0
  jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
777
0
  return buffer;
778
0
}
779
780
// Deprecated. Preserved for backward compatibility
781
0
String Reader::getFormatedErrorMessages() const {
782
0
  return getFormattedErrorMessages();
783
0
}
784
785
0
String Reader::getFormattedErrorMessages() const {
786
0
  String formattedMessage;
787
0
  for (const auto& error : errors_) {
788
0
    formattedMessage +=
789
0
        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
790
0
    formattedMessage += "  " + error.message_ + "\n";
791
0
    if (error.extra_)
792
0
      formattedMessage +=
793
0
          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
794
0
  }
795
0
  return formattedMessage;
796
0
}
797
798
0
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
799
0
  std::vector<Reader::StructuredError> allErrors;
800
0
  for (const auto& error : errors_) {
801
0
    Reader::StructuredError structured;
802
0
    structured.offset_start = error.token_.start_ - begin_;
803
0
    structured.offset_limit = error.token_.end_ - begin_;
804
0
    structured.message = error.message_;
805
0
    allErrors.push_back(structured);
806
0
  }
807
0
  return allErrors;
808
0
}
809
810
0
bool Reader::pushError(const Value& value, const String& message) {
811
0
  ptrdiff_t const length = end_ - begin_;
812
0
  if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
813
0
    return false;
814
0
  Token token;
815
0
  token.type_ = tokenError;
816
0
  token.start_ = begin_ + value.getOffsetStart();
817
0
  token.end_ = begin_ + value.getOffsetLimit();
818
0
  ErrorInfo info;
819
0
  info.token_ = token;
820
0
  info.message_ = message;
821
0
  info.extra_ = nullptr;
822
0
  errors_.push_back(info);
823
0
  return true;
824
0
}
825
826
bool Reader::pushError(const Value& value, const String& message,
827
0
                       const Value& extra) {
828
0
  ptrdiff_t const length = end_ - begin_;
829
0
  if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
830
0
      extra.getOffsetLimit() > length)
831
0
    return false;
832
0
  Token token;
833
0
  token.type_ = tokenError;
834
0
  token.start_ = begin_ + value.getOffsetStart();
835
0
  token.end_ = begin_ + value.getOffsetLimit();
836
0
  ErrorInfo info;
837
0
  info.token_ = token;
838
0
  info.message_ = message;
839
0
  info.extra_ = begin_ + extra.getOffsetStart();
840
0
  errors_.push_back(info);
841
0
  return true;
842
0
}
843
844
0
bool Reader::good() const { return errors_.empty(); }
845
846
// Originally copied from the Features class (now deprecated), used internally
847
// for features implementation.
848
class OurFeatures {
849
public:
850
  static OurFeatures all();
851
  bool allowComments_;
852
  bool allowTrailingCommas_;
853
  bool strictRoot_;
854
  bool allowDroppedNullPlaceholders_;
855
  bool allowNumericKeys_;
856
  bool allowSingleQuotes_;
857
  bool failIfExtra_;
858
  bool rejectDupKeys_;
859
  bool allowSpecialFloats_;
860
  bool skipBom_;
861
  size_t stackLimit_;
862
}; // OurFeatures
863
864
5.97k
OurFeatures OurFeatures::all() { return {}; }
865
866
// Implementation of class Reader
867
// ////////////////////////////////
868
869
// Originally copied from the Reader class (now deprecated), used internally
870
// for implementing JSON reading.
871
class OurReader {
872
public:
873
  using Char = char;
874
  using Location = const Char*;
875
876
  explicit OurReader(OurFeatures const& features);
877
  bool parse(const char* beginDoc, const char* endDoc, Value& root,
878
             bool collectComments = true);
879
  String getFormattedErrorMessages() const;
880
  std::vector<CharReader::StructuredError> getStructuredErrors() const;
881
882
private:
883
  OurReader(OurReader const&);      // no impl
884
  void operator=(OurReader const&); // no impl
885
886
  enum TokenType {
887
    tokenEndOfStream = 0,
888
    tokenObjectBegin,
889
    tokenObjectEnd,
890
    tokenArrayBegin,
891
    tokenArrayEnd,
892
    tokenString,
893
    tokenNumber,
894
    tokenTrue,
895
    tokenFalse,
896
    tokenNull,
897
    tokenNaN,
898
    tokenPosInf,
899
    tokenNegInf,
900
    tokenArraySeparator,
901
    tokenMemberSeparator,
902
    tokenComment,
903
    tokenError
904
  };
905
906
  class Token {
907
  public:
908
    TokenType type_;
909
    Location start_;
910
    Location end_;
911
  };
912
913
  class ErrorInfo {
914
  public:
915
    Token token_;
916
    String message_;
917
    Location extra_;
918
  };
919
920
  using Errors = std::deque<ErrorInfo>;
921
922
  bool readToken(Token& token);
923
  bool readTokenSkippingComments(Token& token);
924
  void skipSpaces();
925
  void skipBom(bool skipBom);
926
  bool match(const Char* pattern, int patternLength);
927
  bool readComment();
928
  bool readCStyleComment(bool* containsNewLineResult);
929
  bool readCppStyleComment();
930
  bool readString();
931
  bool readStringSingleQuote();
932
  bool readNumber(bool checkInf);
933
  bool readValue();
934
  bool readObject(Token& token);
935
  bool readArray(Token& token);
936
  bool decodeNumber(Token& token);
937
  bool decodeNumber(Token& token, Value& decoded);
938
  bool decodeString(Token& token);
939
  bool decodeString(Token& token, String& decoded);
940
  bool decodeDouble(Token& token);
941
  bool decodeDouble(Token& token, Value& decoded);
942
  bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
943
                              unsigned int& unicode);
944
  bool decodeUnicodeEscapeSequence(Token& token, Location& current,
945
                                   Location end, unsigned int& unicode);
946
  bool addError(const String& message, Token& token, Location extra = nullptr);
947
  bool recoverFromError(TokenType skipUntilToken);
948
  bool addErrorAndRecover(const String& message, Token& token,
949
                          TokenType skipUntilToken);
950
  void skipUntilSpace();
951
  Value& currentValue();
952
  Char getNextChar();
953
  void getLocationLineAndColumn(Location location, int& line,
954
                                int& column) const;
955
  String getLocationLineAndColumn(Location location) const;
956
  void addComment(Location begin, Location end, CommentPlacement placement);
957
958
  static String normalizeEOL(Location begin, Location end);
959
  static bool containsNewLine(Location begin, Location end);
960
961
  using Nodes = std::stack<Value*>;
962
963
  Nodes nodes_{};
964
  Errors errors_{};
965
  String document_{};
966
  Location begin_ = nullptr;
967
  Location end_ = nullptr;
968
  Location current_ = nullptr;
969
  Location lastValueEnd_ = nullptr;
970
  Value* lastValue_ = nullptr;
971
  bool lastValueHasAComment_ = false;
972
  String commentsBefore_{};
973
974
  OurFeatures const features_;
975
  bool collectComments_ = false;
976
}; // OurReader
977
978
// complete copy of Read impl, for OurReader
979
980
bool OurReader::containsNewLine(OurReader::Location begin,
981
121k
                                OurReader::Location end) {
982
21.8G
  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
983
121k
}
984
985
5.97k
OurReader::OurReader(OurFeatures const& features) : features_(features) {}
986
987
bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
988
5.97k
                      bool collectComments) {
989
5.97k
  if (!features_.allowComments_) {
990
0
    collectComments = false;
991
0
  }
992
993
5.97k
  begin_ = beginDoc;
994
5.97k
  end_ = endDoc;
995
5.97k
  collectComments_ = collectComments;
996
5.97k
  current_ = begin_;
997
5.97k
  lastValueEnd_ = nullptr;
998
5.97k
  lastValue_ = nullptr;
999
5.97k
  commentsBefore_.clear();
1000
5.97k
  errors_.clear();
1001
5.97k
  while (!nodes_.empty())
1002
0
    nodes_.pop();
1003
5.97k
  nodes_.push(&root);
1004
1005
  // skip byte order mark if it exists at the beginning of the UTF-8 text.
1006
5.97k
  skipBom(features_.skipBom_);
1007
5.97k
  bool successful = readValue();
1008
5.97k
  nodes_.pop();
1009
5.97k
  Token token;
1010
5.97k
  readTokenSkippingComments(token);
1011
5.97k
  if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
1012
199
    addError("Extra non-whitespace after JSON value.", token);
1013
199
    return false;
1014
199
  }
1015
5.78k
  if (collectComments_ && !commentsBefore_.empty())
1016
230
    root.setComment(commentsBefore_, commentAfter);
1017
5.78k
  if (features_.strictRoot_) {
1018
0
    if (!root.isArray() && !root.isObject()) {
1019
      // Set error location to start of doc, ideally should be first token found
1020
      // in doc
1021
0
      token.type_ = tokenError;
1022
0
      token.start_ = beginDoc;
1023
0
      token.end_ = endDoc;
1024
0
      addError(
1025
0
          "A valid JSON document must be either an array or an object value.",
1026
0
          token);
1027
0
      return false;
1028
0
    }
1029
0
  }
1030
5.78k
  return successful;
1031
5.78k
}
1032
1033
2.20M
bool OurReader::readValue() {
1034
  //  To preserve the old behaviour we cast size_t to int.
1035
2.20M
  if (nodes_.size() > features_.stackLimit_)
1036
59
    throwRuntimeError("Exceeded stackLimit in readValue().");
1037
2.20M
  Token token;
1038
2.20M
  readTokenSkippingComments(token);
1039
2.20M
  bool successful = true;
1040
1041
2.20M
  if (collectComments_ && !commentsBefore_.empty()) {
1042
3.70k
    currentValue().setComment(commentsBefore_, commentBefore);
1043
3.70k
    commentsBefore_.clear();
1044
3.70k
  }
1045
1046
2.20M
  switch (token.type_) {
1047
33.5k
  case tokenObjectBegin:
1048
33.5k
    successful = readObject(token);
1049
33.5k
    currentValue().setOffsetLimit(current_ - begin_);
1050
33.5k
    break;
1051
128k
  case tokenArrayBegin:
1052
128k
    successful = readArray(token);
1053
128k
    currentValue().setOffsetLimit(current_ - begin_);
1054
128k
    break;
1055
2.03M
  case tokenNumber:
1056
2.03M
    successful = decodeNumber(token);
1057
2.03M
    break;
1058
1.84k
  case tokenString:
1059
1.84k
    successful = decodeString(token);
1060
1.84k
    break;
1061
2.86k
  case tokenTrue: {
1062
2.86k
    Value v(true);
1063
2.86k
    currentValue().swapPayload(v);
1064
2.86k
    currentValue().setOffsetStart(token.start_ - begin_);
1065
2.86k
    currentValue().setOffsetLimit(token.end_ - begin_);
1066
2.86k
  } break;
1067
439
  case tokenFalse: {
1068
439
    Value v(false);
1069
439
    currentValue().swapPayload(v);
1070
439
    currentValue().setOffsetStart(token.start_ - begin_);
1071
439
    currentValue().setOffsetLimit(token.end_ - begin_);
1072
439
  } break;
1073
3.08k
  case tokenNull: {
1074
3.08k
    Value v;
1075
3.08k
    currentValue().swapPayload(v);
1076
3.08k
    currentValue().setOffsetStart(token.start_ - begin_);
1077
3.08k
    currentValue().setOffsetLimit(token.end_ - begin_);
1078
3.08k
  } break;
1079
0
  case tokenNaN: {
1080
0
    Value v(std::numeric_limits<double>::quiet_NaN());
1081
0
    currentValue().swapPayload(v);
1082
0
    currentValue().setOffsetStart(token.start_ - begin_);
1083
0
    currentValue().setOffsetLimit(token.end_ - begin_);
1084
0
  } break;
1085
0
  case tokenPosInf: {
1086
0
    Value v(std::numeric_limits<double>::infinity());
1087
0
    currentValue().swapPayload(v);
1088
0
    currentValue().setOffsetStart(token.start_ - begin_);
1089
0
    currentValue().setOffsetLimit(token.end_ - begin_);
1090
0
  } break;
1091
0
  case tokenNegInf: {
1092
0
    Value v(-std::numeric_limits<double>::infinity());
1093
0
    currentValue().swapPayload(v);
1094
0
    currentValue().setOffsetStart(token.start_ - begin_);
1095
0
    currentValue().setOffsetLimit(token.end_ - begin_);
1096
0
  } break;
1097
20
  case tokenArraySeparator:
1098
41
  case tokenObjectEnd:
1099
51
  case tokenArrayEnd:
1100
51
    if (features_.allowDroppedNullPlaceholders_) {
1101
      // "Un-read" the current token and mark the current value as a null
1102
      // token.
1103
0
      current_--;
1104
0
      Value v;
1105
0
      currentValue().swapPayload(v);
1106
0
      currentValue().setOffsetStart(current_ - begin_ - 1);
1107
0
      currentValue().setOffsetLimit(current_ - begin_);
1108
0
      break;
1109
0
    } // else, fall through ...
1110
1.74k
  default:
1111
1.74k
    currentValue().setOffsetStart(token.start_ - begin_);
1112
1.74k
    currentValue().setOffsetLimit(token.end_ - begin_);
1113
1.74k
    return addError("Syntax error: value, object or array expected.", token);
1114
2.20M
  }
1115
1116
2.14M
  if (collectComments_) {
1117
906k
    lastValueEnd_ = current_;
1118
906k
    lastValueHasAComment_ = false;
1119
906k
    lastValue_ = &currentValue();
1120
906k
  }
1121
1122
2.14M
  return successful;
1123
2.20M
}
1124
1125
4.35M
bool OurReader::readTokenSkippingComments(Token& token) {
1126
4.35M
  bool success = readToken(token);
1127
4.35M
  if (features_.allowComments_) {
1128
4.37M
    while (success && token.type_ == tokenComment) {
1129
18.1k
      success = readToken(token);
1130
18.1k
    }
1131
4.35M
  }
1132
4.35M
  return success;
1133
4.35M
}
1134
1135
6.17M
bool OurReader::readToken(Token& token) {
1136
6.17M
  skipSpaces();
1137
6.17M
  token.start_ = current_;
1138
6.17M
  Char c = getNextChar();
1139
6.17M
  bool ok = true;
1140
6.17M
  switch (c) {
1141
35.4k
  case '{':
1142
35.4k
    token.type_ = tokenObjectBegin;
1143
35.4k
    break;
1144
6.55k
  case '}':
1145
6.55k
    token.type_ = tokenObjectEnd;
1146
6.55k
    break;
1147
165k
  case '[':
1148
165k
    token.type_ = tokenArrayBegin;
1149
165k
    break;
1150
3.95k
  case ']':
1151
3.95k
    token.type_ = tokenArrayEnd;
1152
3.95k
    break;
1153
122k
  case '"':
1154
122k
    token.type_ = tokenString;
1155
122k
    ok = readString();
1156
122k
    break;
1157
2.67k
  case '\'':
1158
2.67k
    if (features_.allowSingleQuotes_) {
1159
0
      token.type_ = tokenString;
1160
0
      ok = readStringSingleQuote();
1161
2.67k
    } else {
1162
      // If we don't allow single quotes, this is a failure case.
1163
2.67k
      ok = false;
1164
2.67k
    }
1165
2.67k
    break;
1166
155k
  case '/':
1167
155k
    token.type_ = tokenComment;
1168
155k
    ok = readComment();
1169
155k
    break;
1170
85.7k
  case '0':
1171
109k
  case '1':
1172
116k
  case '2':
1173
167k
  case '3':
1174
2.30M
  case '4':
1175
2.30M
  case '5':
1176
2.31M
  case '6':
1177
2.31M
  case '7':
1178
2.33M
  case '8':
1179
2.33M
  case '9':
1180
2.33M
    token.type_ = tokenNumber;
1181
2.33M
    readNumber(false);
1182
2.33M
    break;
1183
140k
  case '-':
1184
140k
    if (readNumber(true)) {
1185
139k
      token.type_ = tokenNumber;
1186
139k
    } else {
1187
522
      token.type_ = tokenNegInf;
1188
522
      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1189
522
    }
1190
140k
    break;
1191
3.86k
  case '+':
1192
3.86k
    if (readNumber(true)) {
1193
3.34k
      token.type_ = tokenNumber;
1194
3.34k
    } else {
1195
526
      token.type_ = tokenPosInf;
1196
526
      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1197
526
    }
1198
3.86k
    break;
1199
87.8k
  case 't':
1200
87.8k
    token.type_ = tokenTrue;
1201
87.8k
    ok = match("rue", 3);
1202
87.8k
    break;
1203
28.5k
  case 'f':
1204
28.5k
    token.type_ = tokenFalse;
1205
28.5k
    ok = match("alse", 4);
1206
28.5k
    break;
1207
13.5k
  case 'n':
1208
13.5k
    token.type_ = tokenNull;
1209
13.5k
    ok = match("ull", 3);
1210
13.5k
    break;
1211
796
  case 'N':
1212
796
    if (features_.allowSpecialFloats_) {
1213
0
      token.type_ = tokenNaN;
1214
0
      ok = match("aN", 2);
1215
796
    } else {
1216
796
      ok = false;
1217
796
    }
1218
796
    break;
1219
1.14k
  case 'I':
1220
1.14k
    if (features_.allowSpecialFloats_) {
1221
0
      token.type_ = tokenPosInf;
1222
0
      ok = match("nfinity", 7);
1223
1.14k
    } else {
1224
1.14k
      ok = false;
1225
1.14k
    }
1226
1.14k
    break;
1227
2.47M
  case ',':
1228
2.47M
    token.type_ = tokenArraySeparator;
1229
2.47M
    break;
1230
101k
  case ':':
1231
101k
    token.type_ = tokenMemberSeparator;
1232
101k
    break;
1233
101k
  case 0:
1234
101k
    token.type_ = tokenEndOfStream;
1235
101k
    break;
1236
394k
  default:
1237
394k
    ok = false;
1238
394k
    break;
1239
6.17M
  }
1240
6.17M
  if (!ok)
1241
526k
    token.type_ = tokenError;
1242
6.17M
  token.end_ = current_;
1243
6.17M
  return ok;
1244
6.17M
}
1245
1246
8.28M
void OurReader::skipSpaces() {
1247
8.29M
  while (current_ != end_) {
1248
8.19M
    Char c = *current_;
1249
8.19M
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1250
7.41k
      ++current_;
1251
8.18M
    else
1252
8.18M
      break;
1253
8.19M
  }
1254
8.28M
}
1255
1256
5.97k
void OurReader::skipBom(bool skipBom) {
1257
  // The default behavior is to skip BOM.
1258
5.97k
  if (skipBom) {
1259
5.97k
    if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
1260
2
      begin_ += 3;
1261
2
      current_ = begin_;
1262
2
    }
1263
5.97k
  }
1264
5.97k
}
1265
1266
129k
bool OurReader::match(const Char* pattern, int patternLength) {
1267
129k
  if (end_ - current_ < patternLength)
1268
91
    return false;
1269
129k
  int index = patternLength;
1270
270k
  while (index--)
1271
251k
    if (current_[index] != pattern[index])
1272
110k
      return false;
1273
18.7k
  current_ += patternLength;
1274
18.7k
  return true;
1275
129k
}
1276
1277
155k
bool OurReader::readComment() {
1278
155k
  const Location commentBegin = current_ - 1;
1279
155k
  const Char c = getNextChar();
1280
155k
  bool successful = false;
1281
155k
  bool cStyleWithEmbeddedNewline = false;
1282
1283
155k
  const bool isCStyleComment = (c == '*');
1284
155k
  const bool isCppStyleComment = (c == '/');
1285
155k
  if (isCStyleComment) {
1286
67.4k
    successful = readCStyleComment(&cStyleWithEmbeddedNewline);
1287
88.3k
  } else if (isCppStyleComment) {
1288
75.4k
    successful = readCppStyleComment();
1289
75.4k
  }
1290
1291
155k
  if (!successful)
1292
12.9k
    return false;
1293
1294
142k
  if (collectComments_) {
1295
136k
    CommentPlacement placement = commentBefore;
1296
1297
136k
    if (!lastValueHasAComment_) {
1298
134k
      if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1299
3.19k
        if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
1300
2.80k
          placement = commentAfterOnSameLine;
1301
2.80k
          lastValueHasAComment_ = true;
1302
2.80k
        }
1303
3.19k
      }
1304
134k
    }
1305
1306
136k
    addComment(commentBegin, current_, placement);
1307
136k
  }
1308
142k
  return true;
1309
155k
}
1310
1311
String OurReader::normalizeEOL(OurReader::Location begin,
1312
136k
                               OurReader::Location end) {
1313
136k
  String normalized;
1314
136k
  normalized.reserve(static_cast<size_t>(end - begin));
1315
136k
  OurReader::Location current = begin;
1316
7.81M
  while (current != end) {
1317
7.67M
    char c = *current++;
1318
7.67M
    if (c == '\r') {
1319
58.6k
      if (current != end && *current == '\n')
1320
        // convert dos EOL
1321
559
        ++current;
1322
      // convert Mac EOL
1323
58.6k
      normalized += '\n';
1324
7.61M
    } else {
1325
7.61M
      normalized += c;
1326
7.61M
    }
1327
7.67M
  }
1328
136k
  return normalized;
1329
136k
}
1330
1331
void OurReader::addComment(Location begin, Location end,
1332
136k
                           CommentPlacement placement) {
1333
136k
  assert(collectComments_);
1334
136k
  const String& normalized = normalizeEOL(begin, end);
1335
136k
  if (placement == commentAfterOnSameLine) {
1336
2.80k
    assert(lastValue_ != nullptr);
1337
2.80k
    lastValue_->setComment(normalized, placement);
1338
133k
  } else {
1339
133k
    commentsBefore_ += normalized;
1340
133k
  }
1341
136k
}
1342
1343
67.4k
bool OurReader::readCStyleComment(bool* containsNewLineResult) {
1344
67.4k
  *containsNewLineResult = false;
1345
1346
1.14M
  while ((current_ + 1) < end_) {
1347
1.14M
    Char c = getNextChar();
1348
1.14M
    if (c == '*' && *current_ == '/')
1349
67.3k
      break;
1350
1.07M
    if (c == '\n')
1351
3.48k
      *containsNewLineResult = true;
1352
1.07M
  }
1353
1354
67.4k
  return getNextChar() == '/';
1355
67.4k
}
1356
1357
75.4k
bool OurReader::readCppStyleComment() {
1358
7.51M
  while (current_ != end_) {
1359
7.51M
    Char c = getNextChar();
1360
7.51M
    if (c == '\n')
1361
16.0k
      break;
1362
7.49M
    if (c == '\r') {
1363
      // Consume DOS EOL. It will be normalized in addComment.
1364
59.0k
      if (current_ != end_ && *current_ == '\n')
1365
419
        getNextChar();
1366
      // Break on Moc OS 9 EOL.
1367
59.0k
      break;
1368
59.0k
    }
1369
7.49M
  }
1370
75.4k
  return true;
1371
75.4k
}
1372
1373
2.47M
bool OurReader::readNumber(bool checkInf) {
1374
2.47M
  Location p = current_;
1375
2.47M
  if (checkInf && p != end_ && *p == 'I') {
1376
1.04k
    current_ = ++p;
1377
1.04k
    return false;
1378
1.04k
  }
1379
2.47M
  char c = '0'; // stopgap for already consumed character
1380
  // integral part
1381
16.7M
  while (c >= '0' && c <= '9')
1382
14.3M
    c = (current_ = p) < end_ ? *p++ : '\0';
1383
  // fractional part
1384
2.47M
  if (c == '.') {
1385
5.25k
    c = (current_ = p) < end_ ? *p++ : '\0';
1386
2.94M
    while (c >= '0' && c <= '9')
1387
2.94M
      c = (current_ = p) < end_ ? *p++ : '\0';
1388
5.25k
  }
1389
  // exponential part
1390
2.47M
  if (c == 'e' || c == 'E') {
1391
7.49k
    c = (current_ = p) < end_ ? *p++ : '\0';
1392
7.49k
    if (c == '+' || c == '-')
1393
2.51k
      c = (current_ = p) < end_ ? *p++ : '\0';
1394
22.2k
    while (c >= '0' && c <= '9')
1395
14.7k
      c = (current_ = p) < end_ ? *p++ : '\0';
1396
7.49k
  }
1397
2.47M
  return true;
1398
2.47M
}
1399
122k
bool OurReader::readString() {
1400
122k
  Char c = 0;
1401
19.0M
  while (current_ != end_) {
1402
19.0M
    c = getNextChar();
1403
19.0M
    if (c == '\\')
1404
16.2k
      getNextChar();
1405
18.9M
    else if (c == '"')
1406
120k
      break;
1407
19.0M
  }
1408
122k
  return c == '"';
1409
122k
}
1410
1411
0
bool OurReader::readStringSingleQuote() {
1412
0
  Char c = 0;
1413
0
  while (current_ != end_) {
1414
0
    c = getNextChar();
1415
0
    if (c == '\\')
1416
0
      getNextChar();
1417
0
    else if (c == '\'')
1418
0
      break;
1419
0
  }
1420
0
  return c == '\'';
1421
0
}
1422
1423
33.5k
bool OurReader::readObject(Token& token) {
1424
33.5k
  Token tokenName;
1425
33.5k
  String name;
1426
33.5k
  Value init(objectValue);
1427
33.5k
  currentValue().swapPayload(init);
1428
33.5k
  currentValue().setOffsetStart(token.start_ - begin_);
1429
106k
  while (readTokenSkippingComments(tokenName)) {
1430
96.7k
    if (tokenName.type_ == tokenObjectEnd &&
1431
2.61k
        (name.empty() ||
1432
813
         features_.allowTrailingCommas_)) // empty object or trailing comma
1433
2.61k
      return true;
1434
94.1k
    name.clear();
1435
94.1k
    if (tokenName.type_ == tokenString) {
1436
93.9k
      if (!decodeString(tokenName, name))
1437
172
        return recoverFromError(tokenObjectEnd);
1438
93.9k
    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1439
0
      Value numberName;
1440
0
      if (!decodeNumber(tokenName, numberName))
1441
0
        return recoverFromError(tokenObjectEnd);
1442
0
      name = numberName.asString();
1443
151
    } else {
1444
151
      break;
1445
151
    }
1446
93.8k
    if (name.length() >= (1U << 30))
1447
0
      throwRuntimeError("keylength >= 2^30");
1448
93.8k
    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1449
0
      String msg = "Duplicate key: '" + name + "'";
1450
0
      return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1451
0
    }
1452
1453
93.8k
    Token colon;
1454
93.8k
    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1455
616
      return addErrorAndRecover("Missing ':' after object member name", colon,
1456
616
                                tokenObjectEnd);
1457
616
    }
1458
93.1k
    Value& value = currentValue()[name];
1459
93.1k
    nodes_.push(&value);
1460
93.1k
    bool ok = readValue();
1461
93.1k
    nodes_.pop();
1462
93.1k
    if (!ok) // error already set
1463
17.6k
      return recoverFromError(tokenObjectEnd);
1464
1465
75.5k
    Token comma;
1466
75.5k
    if (!readTokenSkippingComments(comma) ||
1467
65.8k
        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator)) {
1468
597
      return addErrorAndRecover("Missing ',' or '}' in object declaration",
1469
597
                                comma, tokenObjectEnd);
1470
597
    }
1471
74.9k
    if (comma.type_ == tokenObjectEnd)
1472
2.33k
      return true;
1473
74.9k
  }
1474
9.57k
  return addErrorAndRecover("Missing '}' or object member name", tokenName,
1475
9.57k
                            tokenObjectEnd);
1476
33.5k
}
1477
1478
128k
bool OurReader::readArray(Token& token) {
1479
128k
  Value init(arrayValue);
1480
128k
  currentValue().swapPayload(init);
1481
128k
  currentValue().setOffsetStart(token.start_ - begin_);
1482
128k
  int index = 0;
1483
2.10M
  for (;;) {
1484
2.10M
    skipSpaces();
1485
2.10M
    if (current_ != end_ && *current_ == ']' &&
1486
1.68k
        (index == 0 ||
1487
716
         (features_.allowTrailingCommas_ &&
1488
716
          !features_.allowDroppedNullPlaceholders_))) // empty array or trailing
1489
                                                      // comma
1490
1.68k
    {
1491
1.68k
      Token endArray;
1492
1.68k
      readToken(endArray);
1493
1.68k
      return true;
1494
1.68k
    }
1495
2.10M
    Value& value = currentValue()[index++];
1496
2.10M
    nodes_.push(&value);
1497
2.10M
    bool ok = readValue();
1498
2.10M
    nodes_.pop();
1499
2.10M
    if (!ok) // error already set
1500
75.5k
      return recoverFromError(tokenArrayEnd);
1501
1502
2.03M
    Token currentToken;
1503
    // Accept Comment after last item in the array.
1504
2.03M
    ok = readTokenSkippingComments(currentToken);
1505
2.03M
    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
1506
2.01k
                         currentToken.type_ != tokenArrayEnd);
1507
2.03M
    if (!ok || badTokenType) {
1508
565
      return addErrorAndRecover("Missing ',' or ']' in array declaration",
1509
565
                                currentToken, tokenArrayEnd);
1510
565
    }
1511
2.03M
    if (currentToken.type_ == tokenArrayEnd)
1512
1.44k
      break;
1513
2.03M
  }
1514
51.1k
  return true;
1515
128k
}
1516
1517
2.03M
bool OurReader::decodeNumber(Token& token) {
1518
2.03M
  Value decoded;
1519
2.03M
  if (!decodeNumber(token, decoded))
1520
339
    return false;
1521
2.03M
  currentValue().swapPayload(decoded);
1522
2.03M
  currentValue().setOffsetStart(token.start_ - begin_);
1523
2.03M
  currentValue().setOffsetLimit(token.end_ - begin_);
1524
2.03M
  return true;
1525
2.03M
}
1526
1527
2.03M
bool OurReader::decodeNumber(Token& token, Value& decoded) {
1528
  // Attempts to parse the number as an integer. If the number is
1529
  // larger than the maximum supported value of an integer then
1530
  // we decode the number as a double.
1531
2.03M
  Location current = token.start_;
1532
2.03M
  const bool isNegative = *current == '-';
1533
2.03M
  if (isNegative) {
1534
134k
    ++current;
1535
134k
  }
1536
1537
  // We assume we can represent the largest and smallest integer types as
1538
  // unsigned integers with separate sign. This is only true if they can fit
1539
  // into an unsigned integer.
1540
2.03M
  static_assert(Value::maxLargestInt <= Value::maxLargestUInt,
1541
2.03M
                "Int must be smaller than UInt");
1542
1543
  // We need to convert minLargestInt into a positive number. The easiest way
1544
  // to do this conversion is to assume our "threshold" value of minLargestInt
1545
  // divided by 10 can fit in maxLargestInt when absolute valued. This should
1546
  // be a safe assumption.
1547
2.03M
  static_assert(Value::minLargestInt <= -Value::maxLargestInt,
1548
2.03M
                "The absolute value of minLargestInt must be greater than or "
1549
2.03M
                "equal to maxLargestInt");
1550
2.03M
  static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,
1551
2.03M
                "The absolute value of minLargestInt must be only 1 magnitude "
1552
2.03M
                "larger than maxLargest Int");
1553
1554
2.03M
  static constexpr Value::LargestUInt positive_threshold =
1555
2.03M
      Value::maxLargestUInt / 10;
1556
2.03M
  static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10;
1557
1558
  // For the negative values, we have to be more careful. Since typically
1559
  // -Value::minLargestInt will cause an overflow, we first divide by 10 and
1560
  // then take the inverse. This assumes that minLargestInt is only a single
1561
  // power of 10 different in magnitude, which we check above. For the last
1562
  // digit, we take the modulus before negating for the same reason.
1563
2.03M
  static constexpr auto negative_threshold =
1564
2.03M
      Value::LargestUInt(-(Value::minLargestInt / 10));
1565
2.03M
  static constexpr auto negative_last_digit =
1566
2.03M
      Value::UInt(-(Value::minLargestInt % 10));
1567
1568
2.03M
  const Value::LargestUInt threshold =
1569
2.03M
      isNegative ? negative_threshold : positive_threshold;
1570
2.03M
  const Value::UInt max_last_digit =
1571
2.03M
      isNegative ? negative_last_digit : positive_last_digit;
1572
1573
2.03M
  Value::LargestUInt value = 0;
1574
3.99M
  while (current < token.end_) {
1575
1.96M
    Char c = *current++;
1576
1.96M
    if (c < '0' || c > '9')
1577
4.23k
      return decodeDouble(token, decoded);
1578
1579
1.96M
    const auto digit(static_cast<Value::UInt>(c - '0'));
1580
1.96M
    if (value >= threshold) {
1581
      // We've hit or exceeded the max value divided by 10 (rounded down). If
1582
      // a) we've only just touched the limit, meaning value == threshold,
1583
      // b) this is the last digit, or
1584
      // c) it's small enough to fit in that rounding delta, we're okay.
1585
      // Otherwise treat this number as a double to avoid overflow.
1586
2.62k
      if (value > threshold || current != token.end_ ||
1587
2.18k
          digit > max_last_digit) {
1588
2.18k
        return decodeDouble(token, decoded);
1589
2.18k
      }
1590
2.62k
    }
1591
1.96M
    value = value * 10 + digit;
1592
1.96M
  }
1593
1594
2.02M
  if (isNegative) {
1595
    // We use the same magnitude assumption here, just in case.
1596
133k
    const auto last_digit = static_cast<Value::UInt>(value % 10);
1597
133k
    decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
1598
1.89M
  } else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
1599
1.89M
    decoded = Value::LargestInt(value);
1600
1.89M
  } else {
1601
581
    decoded = value;
1602
581
  }
1603
1604
2.02M
  return true;
1605
2.03M
}
1606
1607
0
bool OurReader::decodeDouble(Token& token) {
1608
0
  Value decoded;
1609
0
  if (!decodeDouble(token, decoded))
1610
0
    return false;
1611
0
  currentValue().swapPayload(decoded);
1612
0
  currentValue().setOffsetStart(token.start_ - begin_);
1613
0
  currentValue().setOffsetLimit(token.end_ - begin_);
1614
0
  return true;
1615
0
}
1616
1617
6.42k
bool OurReader::decodeDouble(Token& token, Value& decoded) {
1618
6.42k
  double value = 0;
1619
6.42k
  IStringStream is(String(token.start_, token.end_));
1620
6.42k
  if (!(is >> value)) {
1621
1.06k
    if (value == std::numeric_limits<double>::max())
1622
0
      value = std::numeric_limits<double>::infinity();
1623
1.06k
    else if (value == std::numeric_limits<double>::lowest())
1624
0
      value = -std::numeric_limits<double>::infinity();
1625
1.06k
    else if (!std::isinf(value))
1626
339
      return addError(
1627
339
          "'" + String(token.start_, token.end_) + "' is not a number.", token);
1628
1.06k
  }
1629
6.08k
  decoded = value;
1630
6.08k
  return true;
1631
6.42k
}
1632
1633
1.84k
bool OurReader::decodeString(Token& token) {
1634
1.84k
  String decoded_string;
1635
1.84k
  if (!decodeString(token, decoded_string))
1636
180
    return false;
1637
1.66k
  Value decoded(decoded_string);
1638
1.66k
  currentValue().swapPayload(decoded);
1639
1.66k
  currentValue().setOffsetStart(token.start_ - begin_);
1640
1.66k
  currentValue().setOffsetLimit(token.end_ - begin_);
1641
1.66k
  return true;
1642
1.84k
}
1643
1644
95.8k
bool OurReader::decodeString(Token& token, String& decoded) {
1645
95.8k
  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1646
95.8k
  Location current = token.start_ + 1; // skip '"'
1647
95.8k
  Location end = token.end_ - 1;       // do not include '"'
1648
16.2M
  while (current != end) {
1649
16.2M
    Char c = *current++;
1650
16.2M
    if (c == '"')
1651
0
      break;
1652
16.2M
    if (c == '\\') {
1653
12.2k
      if (current == end)
1654
0
        return addError("Empty escape sequence in string", token, current);
1655
12.2k
      Char escape = *current++;
1656
12.2k
      switch (escape) {
1657
847
      case '"':
1658
847
        decoded += '"';
1659
847
        break;
1660
488
      case '/':
1661
488
        decoded += '/';
1662
488
        break;
1663
1.13k
      case '\\':
1664
1.13k
        decoded += '\\';
1665
1.13k
        break;
1666
2.75k
      case 'b':
1667
2.75k
        decoded += '\b';
1668
2.75k
        break;
1669
868
      case 'f':
1670
868
        decoded += '\f';
1671
868
        break;
1672
797
      case 'n':
1673
797
        decoded += '\n';
1674
797
        break;
1675
595
      case 'r':
1676
595
        decoded += '\r';
1677
595
        break;
1678
825
      case 't':
1679
825
        decoded += '\t';
1680
825
        break;
1681
3.91k
      case 'u': {
1682
3.91k
        unsigned int unicode;
1683
3.91k
        if (!decodeUnicodeCodePoint(token, current, end, unicode))
1684
329
          return false;
1685
3.58k
        decoded += codePointToUTF8(unicode);
1686
3.58k
      } break;
1687
23
      default:
1688
23
        return addError("Bad escape sequence in string", token, current);
1689
12.2k
      }
1690
16.1M
    } else {
1691
16.1M
      decoded += c;
1692
16.1M
    }
1693
16.2M
  }
1694
95.4k
  return true;
1695
95.8k
}
1696
1697
bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
1698
3.91k
                                       Location end, unsigned int& unicode) {
1699
1700
3.91k
  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1701
248
    return false;
1702
3.67k
  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1703
    // surrogate pairs
1704
1.22k
    if (end - current < 6)
1705
15
      return addError(
1706
15
          "additional six characters expected to parse unicode surrogate pair.",
1707
15
          token, current);
1708
1.20k
    if (*(current++) == '\\' && *(current++) == 'u') {
1709
1.15k
      unsigned int surrogatePair;
1710
1.15k
      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1711
1.14k
        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1712
1.14k
      } else
1713
10
        return false;
1714
1.15k
    } else
1715
56
      return addError("expecting another \\u token to begin the second half of "
1716
56
                      "a unicode surrogate pair",
1717
56
                      token, current);
1718
1.20k
  }
1719
3.58k
  return true;
1720
3.67k
}
1721
1722
bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
1723
                                            Location end,
1724
5.07k
                                            unsigned int& ret_unicode) {
1725
5.07k
  if (end - current < 4)
1726
19
    return addError(
1727
19
        "Bad unicode escape sequence in string: four digits expected.", token,
1728
19
        current);
1729
5.05k
  int unicode = 0;
1730
24.6k
  for (int index = 0; index < 4; ++index) {
1731
19.8k
    Char c = *current++;
1732
19.8k
    unicode *= 16;
1733
19.8k
    if (c >= '0' && c <= '9')
1734
7.16k
      unicode += c - '0';
1735
12.6k
    else if (c >= 'a' && c <= 'f')
1736
5.93k
      unicode += c - 'a' + 10;
1737
6.75k
    else if (c >= 'A' && c <= 'F')
1738
6.51k
      unicode += c - 'A' + 10;
1739
239
    else
1740
239
      return addError(
1741
239
          "Bad unicode escape sequence in string: hexadecimal digit expected.",
1742
239
          token, current);
1743
19.8k
  }
1744
4.81k
  ret_unicode = static_cast<unsigned int>(unicode);
1745
4.81k
  return true;
1746
5.05k
}
1747
1748
4.67k
bool OurReader::addError(const String& message, Token& token, Location extra) {
1749
4.67k
  ErrorInfo info;
1750
4.67k
  info.token_ = token;
1751
4.67k
  info.message_ = message;
1752
4.67k
  info.extra_ = extra;
1753
4.67k
  errors_.push_back(info);
1754
4.67k
  return false;
1755
4.67k
}
1756
1757
95.4k
bool OurReader::recoverFromError(TokenType skipUntilToken) {
1758
95.4k
  size_t errorCount = errors_.size();
1759
95.4k
  Token skip;
1760
1.70M
  for (;;) {
1761
1.70M
    if (!readToken(skip))
1762
524k
      errors_.resize(errorCount); // discard errors caused by recovery
1763
1.70M
    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1764
95.4k
      break;
1765
1.70M
  }
1766
95.4k
  errors_.resize(errorCount);
1767
95.4k
  return false;
1768
95.4k
}
1769
1770
bool OurReader::addErrorAndRecover(const String& message, Token& token,
1771
2.03k
                                   TokenType skipUntilToken) {
1772
2.03k
  addError(message, token);
1773
2.03k
  return recoverFromError(skipUntilToken);
1774
2.03k
}
1775
1776
9.66M
Value& OurReader::currentValue() { return *(nodes_.top()); }
1777
1778
34.0M
OurReader::Char OurReader::getNextChar() {
1779
34.0M
  if (current_ == end_)
1780
100k
    return 0;
1781
33.9M
  return *current_++;
1782
34.0M
}
1783
1784
void OurReader::getLocationLineAndColumn(Location location, int& line,
1785
0
                                         int& column) const {
1786
0
  Location current = begin_;
1787
0
  Location lastLineStart = current;
1788
0
  line = 0;
1789
0
  while (current < location && current != end_) {
1790
0
    Char c = *current++;
1791
0
    if (c == '\r') {
1792
0
      if (current != end_ && *current == '\n')
1793
0
        ++current;
1794
0
      lastLineStart = current;
1795
0
      ++line;
1796
0
    } else if (c == '\n') {
1797
0
      lastLineStart = current;
1798
0
      ++line;
1799
0
    }
1800
0
  }
1801
  // column & line start at 1
1802
0
  column = int(location - lastLineStart) + 1;
1803
0
  ++line;
1804
0
}
1805
1806
0
String OurReader::getLocationLineAndColumn(Location location) const {
1807
0
  int line, column;
1808
0
  getLocationLineAndColumn(location, line, column);
1809
0
  char buffer[18 + 16 + 16 + 1];
1810
0
  jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
1811
0
  return buffer;
1812
0
}
1813
1814
0
String OurReader::getFormattedErrorMessages() const {
1815
0
  String formattedMessage;
1816
0
  for (const auto& error : errors_) {
1817
0
    formattedMessage +=
1818
0
        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
1819
0
    formattedMessage += "  " + error.message_ + "\n";
1820
0
    if (error.extra_)
1821
0
      formattedMessage +=
1822
0
          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
1823
0
  }
1824
0
  return formattedMessage;
1825
0
}
1826
1827
std::vector<CharReader::StructuredError>
1828
0
OurReader::getStructuredErrors() const {
1829
0
  std::vector<CharReader::StructuredError> allErrors;
1830
0
  for (const auto& error : errors_) {
1831
0
    CharReader::StructuredError structured;
1832
0
    structured.offset_start = error.token_.start_ - begin_;
1833
0
    structured.offset_limit = error.token_.end_ - begin_;
1834
0
    structured.message = error.message_;
1835
0
    allErrors.push_back(structured);
1836
0
  }
1837
0
  return allErrors;
1838
0
}
1839
1840
class OurCharReader : public CharReader {
1841
1842
public:
1843
  OurCharReader(bool collectComments, OurFeatures const& features)
1844
5.97k
      : CharReader(
1845
5.97k
            std::unique_ptr<OurImpl>(new OurImpl(collectComments, features))) {}
1846
1847
protected:
1848
  class OurImpl : public Impl {
1849
  public:
1850
    OurImpl(bool collectComments, OurFeatures const& features)
1851
5.97k
        : collectComments_(collectComments), reader_(features) {}
1852
1853
    bool parse(char const* beginDoc, char const* endDoc, Value* root,
1854
5.97k
               String* errs) override {
1855
5.97k
      bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1856
5.97k
      if (errs) {
1857
0
        *errs = reader_.getFormattedErrorMessages();
1858
0
      }
1859
5.97k
      return ok;
1860
5.97k
    }
1861
1862
    std::vector<CharReader::StructuredError>
1863
0
    getStructuredErrors() const override {
1864
0
      return reader_.getStructuredErrors();
1865
0
    }
1866
1867
  private:
1868
    bool const collectComments_;
1869
    OurReader reader_;
1870
  };
1871
};
1872
1873
5.98k
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
1874
5.98k
CharReaderBuilder::~CharReaderBuilder() = default;
1875
5.97k
CharReader* CharReaderBuilder::newCharReader() const {
1876
5.97k
  bool collectComments = settings_["collectComments"].asBool();
1877
5.97k
  OurFeatures features = OurFeatures::all();
1878
5.97k
  features.allowComments_ = settings_["allowComments"].asBool();
1879
5.97k
  features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
1880
5.97k
  features.strictRoot_ = settings_["strictRoot"].asBool();
1881
5.97k
  features.allowDroppedNullPlaceholders_ =
1882
5.97k
      settings_["allowDroppedNullPlaceholders"].asBool();
1883
5.97k
  features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
1884
5.97k
  features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
1885
1886
  // Stack limit is always a size_t, so we get this as an unsigned int
1887
  // regardless of it we have 64-bit integer support enabled.
1888
5.97k
  features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());
1889
5.97k
  features.failIfExtra_ = settings_["failIfExtra"].asBool();
1890
5.97k
  features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
1891
5.97k
  features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
1892
5.97k
  features.skipBom_ = settings_["skipBom"].asBool();
1893
5.97k
  return new OurCharReader(collectComments, features);
1894
5.97k
}
1895
1896
0
bool CharReaderBuilder::validate(Json::Value* invalid) const {
1897
0
  static const auto& valid_keys = *new std::set<String>{
1898
0
      "collectComments",
1899
0
      "allowComments",
1900
0
      "allowTrailingCommas",
1901
0
      "strictRoot",
1902
0
      "allowDroppedNullPlaceholders",
1903
0
      "allowNumericKeys",
1904
0
      "allowSingleQuotes",
1905
0
      "stackLimit",
1906
0
      "failIfExtra",
1907
0
      "rejectDupKeys",
1908
0
      "allowSpecialFloats",
1909
0
      "skipBom",
1910
0
  };
1911
0
  for (auto si = settings_.begin(); si != settings_.end(); ++si) {
1912
0
    auto key = si.name();
1913
0
    if (valid_keys.count(key))
1914
0
      continue;
1915
0
    if (invalid)
1916
0
      (*invalid)[key] = *si;
1917
0
    else
1918
0
      return false;
1919
0
  }
1920
0
  return invalid ? invalid->empty() : true;
1921
0
}
1922
1923
0
Value& CharReaderBuilder::operator[](const String& key) {
1924
0
  return settings_[key];
1925
0
}
1926
// static
1927
0
void CharReaderBuilder::strictMode(Json::Value* settings) {
1928
  //! [CharReaderBuilderStrictMode]
1929
0
  (*settings)["allowComments"] = false;
1930
0
  (*settings)["allowTrailingCommas"] = false;
1931
0
  (*settings)["strictRoot"] = true;
1932
0
  (*settings)["allowDroppedNullPlaceholders"] = false;
1933
0
  (*settings)["allowNumericKeys"] = false;
1934
0
  (*settings)["allowSingleQuotes"] = false;
1935
0
  (*settings)["stackLimit"] = 1000;
1936
0
  (*settings)["failIfExtra"] = true;
1937
0
  (*settings)["rejectDupKeys"] = true;
1938
0
  (*settings)["allowSpecialFloats"] = false;
1939
0
  (*settings)["skipBom"] = true;
1940
  //! [CharReaderBuilderStrictMode]
1941
0
}
1942
// static
1943
5.98k
void CharReaderBuilder::setDefaults(Json::Value* settings) {
1944
  //! [CharReaderBuilderDefaults]
1945
5.98k
  (*settings)["collectComments"] = true;
1946
5.98k
  (*settings)["allowComments"] = true;
1947
5.98k
  (*settings)["allowTrailingCommas"] = true;
1948
5.98k
  (*settings)["strictRoot"] = false;
1949
5.98k
  (*settings)["allowDroppedNullPlaceholders"] = false;
1950
5.98k
  (*settings)["allowNumericKeys"] = false;
1951
5.98k
  (*settings)["allowSingleQuotes"] = false;
1952
5.98k
  (*settings)["stackLimit"] = 1000;
1953
5.98k
  (*settings)["failIfExtra"] = false;
1954
5.98k
  (*settings)["rejectDupKeys"] = false;
1955
5.98k
  (*settings)["allowSpecialFloats"] = false;
1956
5.98k
  (*settings)["skipBom"] = true;
1957
  //! [CharReaderBuilderDefaults]
1958
5.98k
}
1959
// static
1960
0
void CharReaderBuilder::ecma404Mode(Json::Value* settings) {
1961
  //! [CharReaderBuilderECMA404Mode]
1962
0
  (*settings)["allowComments"] = false;
1963
0
  (*settings)["allowTrailingCommas"] = false;
1964
0
  (*settings)["strictRoot"] = false;
1965
0
  (*settings)["allowDroppedNullPlaceholders"] = false;
1966
0
  (*settings)["allowNumericKeys"] = false;
1967
0
  (*settings)["allowSingleQuotes"] = false;
1968
0
  (*settings)["stackLimit"] = 1000;
1969
0
  (*settings)["failIfExtra"] = true;
1970
0
  (*settings)["rejectDupKeys"] = false;
1971
0
  (*settings)["allowSpecialFloats"] = false;
1972
0
  (*settings)["skipBom"] = false;
1973
  //! [CharReaderBuilderECMA404Mode]
1974
0
}
1975
1976
std::vector<CharReader::StructuredError>
1977
0
CharReader::getStructuredErrors() const {
1978
0
  return _impl->getStructuredErrors();
1979
0
}
1980
1981
bool CharReader::parse(char const* beginDoc, char const* endDoc, Value* root,
1982
5.97k
                       String* errs) {
1983
5.97k
  return _impl->parse(beginDoc, endDoc, root, errs);
1984
5.97k
}
1985
1986
//////////////////////////////////
1987
// global functions
1988
1989
bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
1990
0
                     String* errs) {
1991
0
  OStringStream ssin;
1992
0
  ssin << sin.rdbuf();
1993
0
  String doc = std::move(ssin).str();
1994
0
  char const* begin = doc.data();
1995
0
  char const* end = begin + doc.size();
1996
  // Note that we do not actually need a null-terminator.
1997
0
  CharReaderPtr const reader(fact.newCharReader());
1998
0
  return reader->parse(begin, end, root, errs);
1999
0
}
2000
2001
0
IStream& operator>>(IStream& sin, Value& root) {
2002
0
  CharReaderBuilder b;
2003
0
  String errs;
2004
0
  bool ok = parseFromStream(b, sin, &root, &errs);
2005
0
  if (!ok) {
2006
0
    throwRuntimeError(errs);
2007
0
  }
2008
0
  return sin;
2009
0
}
2010
2011
} // namespace Json