Coverage Report

Created: 2024-07-23 06:31

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