Coverage Report

Created: 2024-02-11 06:16

/src/perfetto/buildtools/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 <cstring>
16
#include <iostream>
17
#include <istream>
18
#include <limits>
19
#include <memory>
20
#include <set>
21
#include <sstream>
22
#include <utility>
23
24
#include <cstdio>
25
#if __cplusplus >= 201103L
26
27
#if !defined(sscanf)
28
#define sscanf std::sscanf
29
#endif
30
31
#endif //__cplusplus
32
33
#if defined(_MSC_VER)
34
#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
35
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
36
#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
37
#endif //_MSC_VER
38
39
#if defined(_MSC_VER)
40
// Disable warning about strdup being deprecated.
41
#pragma warning(disable : 4996)
42
#endif
43
44
// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
45
// time to change the stack limit
46
#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
47
#define JSONCPP_DEPRECATED_STACK_LIMIT 1000
48
#endif
49
50
static size_t const stackLimit_g =
51
    JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
52
53
namespace Json {
54
55
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
56
using CharReaderPtr = std::unique_ptr<CharReader>;
57
#else
58
using CharReaderPtr = std::auto_ptr<CharReader>;
59
#endif
60
61
// Implementation of class Features
62
// ////////////////////////////////
63
64
0
Features::Features() = default;
65
66
0
Features Features::all() { return {}; }
67
68
0
Features Features::strictMode() {
69
0
  Features features;
70
0
  features.allowComments_ = false;
71
0
  features.strictRoot_ = true;
72
0
  features.allowDroppedNullPlaceholders_ = false;
73
0
  features.allowNumericKeys_ = false;
74
0
  return features;
75
0
}
76
77
// Implementation of class Reader
78
// ////////////////////////////////
79
80
0
bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
81
0
  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
82
0
}
83
84
// Class Reader
85
// //////////////////////////////////////////////////////////////////
86
87
0
Reader::Reader() : features_(Features::all()) {}
88
89
0
Reader::Reader(const Features& features) : features_(features) {}
90
91
bool Reader::parse(const std::string& document, Value& root,
92
0
                   bool collectComments) {
93
0
  document_.assign(document.begin(), document.end());
94
0
  const char* begin = document_.c_str();
95
0
  const char* end = begin + document_.length();
96
0
  return parse(begin, end, root, collectComments);
97
0
}
98
99
0
bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
100
  // std::istream_iterator<char> begin(is);
101
  // std::istream_iterator<char> end;
102
  // Those would allow streamed input from a file, if parse() were a
103
  // template function.
104
105
  // Since String is reference-counted, this at least does not
106
  // create an extra copy.
107
0
  String doc;
108
0
  std::getline(is, doc, static_cast<char> EOF);
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
    return addError(
606
0
        "'" + String(token.start_, token.end_) + "' is not a number.", token);
607
0
  decoded = value;
608
0
  return true;
609
0
}
610
611
0
bool Reader::decodeString(Token& token) {
612
0
  String decoded_string;
613
0
  if (!decodeString(token, decoded_string))
614
0
    return false;
615
0
  Value decoded(decoded_string);
616
0
  currentValue().swapPayload(decoded);
617
0
  currentValue().setOffsetStart(token.start_ - begin_);
618
0
  currentValue().setOffsetLimit(token.end_ - begin_);
619
0
  return true;
620
0
}
621
622
0
bool Reader::decodeString(Token& token, String& decoded) {
623
0
  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
624
0
  Location current = token.start_ + 1; // skip '"'
625
0
  Location end = token.end_ - 1;       // do not include '"'
626
0
  while (current != end) {
627
0
    Char c = *current++;
628
0
    if (c == '"')
629
0
      break;
630
0
    if (c == '\\') {
631
0
      if (current == end)
632
0
        return addError("Empty escape sequence in string", token, current);
633
0
      Char escape = *current++;
634
0
      switch (escape) {
635
0
      case '"':
636
0
        decoded += '"';
637
0
        break;
638
0
      case '/':
639
0
        decoded += '/';
640
0
        break;
641
0
      case '\\':
642
0
        decoded += '\\';
643
0
        break;
644
0
      case 'b':
645
0
        decoded += '\b';
646
0
        break;
647
0
      case 'f':
648
0
        decoded += '\f';
649
0
        break;
650
0
      case 'n':
651
0
        decoded += '\n';
652
0
        break;
653
0
      case 'r':
654
0
        decoded += '\r';
655
0
        break;
656
0
      case 't':
657
0
        decoded += '\t';
658
0
        break;
659
0
      case 'u': {
660
0
        unsigned int unicode;
661
0
        if (!decodeUnicodeCodePoint(token, current, end, unicode))
662
0
          return false;
663
0
        decoded += codePointToUTF8(unicode);
664
0
      } break;
665
0
      default:
666
0
        return addError("Bad escape sequence in string", token, current);
667
0
      }
668
0
    } else {
669
0
      decoded += c;
670
0
    }
671
0
  }
672
0
  return true;
673
0
}
674
675
bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
676
0
                                    Location end, unsigned int& unicode) {
677
678
0
  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
679
0
    return false;
680
0
  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
681
    // surrogate pairs
682
0
    if (end - current < 6)
683
0
      return addError(
684
0
          "additional six characters expected to parse unicode surrogate pair.",
685
0
          token, current);
686
0
    if (*(current++) == '\\' && *(current++) == 'u') {
687
0
      unsigned int surrogatePair;
688
0
      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
689
0
        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
690
0
      } else
691
0
        return false;
692
0
    } else
693
0
      return addError("expecting another \\u token to begin the second half of "
694
0
                      "a unicode surrogate pair",
695
0
                      token, current);
696
0
  }
697
0
  return true;
698
0
}
699
700
bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
701
                                         Location end,
702
0
                                         unsigned int& ret_unicode) {
703
0
  if (end - current < 4)
704
0
    return addError(
705
0
        "Bad unicode escape sequence in string: four digits expected.", token,
706
0
        current);
707
0
  int unicode = 0;
708
0
  for (int index = 0; index < 4; ++index) {
709
0
    Char c = *current++;
710
0
    unicode *= 16;
711
0
    if (c >= '0' && c <= '9')
712
0
      unicode += c - '0';
713
0
    else if (c >= 'a' && c <= 'f')
714
0
      unicode += c - 'a' + 10;
715
0
    else if (c >= 'A' && c <= 'F')
716
0
      unicode += c - 'A' + 10;
717
0
    else
718
0
      return addError(
719
0
          "Bad unicode escape sequence in string: hexadecimal digit expected.",
720
0
          token, current);
721
0
  }
722
0
  ret_unicode = static_cast<unsigned int>(unicode);
723
0
  return true;
724
0
}
725
726
0
bool Reader::addError(const String& message, Token& token, Location extra) {
727
0
  ErrorInfo info;
728
0
  info.token_ = token;
729
0
  info.message_ = message;
730
0
  info.extra_ = extra;
731
0
  errors_.push_back(info);
732
0
  return false;
733
0
}
734
735
0
bool Reader::recoverFromError(TokenType skipUntilToken) {
736
0
  size_t const errorCount = errors_.size();
737
0
  Token skip;
738
0
  for (;;) {
739
0
    if (!readToken(skip))
740
0
      errors_.resize(errorCount); // discard errors caused by recovery
741
0
    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
742
0
      break;
743
0
  }
744
0
  errors_.resize(errorCount);
745
0
  return false;
746
0
}
747
748
bool Reader::addErrorAndRecover(const String& message, Token& token,
749
0
                                TokenType skipUntilToken) {
750
0
  addError(message, token);
751
0
  return recoverFromError(skipUntilToken);
752
0
}
753
754
0
Value& Reader::currentValue() { return *(nodes_.top()); }
755
756
0
Reader::Char Reader::getNextChar() {
757
0
  if (current_ == end_)
758
0
    return 0;
759
0
  return *current_++;
760
0
}
761
762
void Reader::getLocationLineAndColumn(Location location, int& line,
763
0
                                      int& column) const {
764
0
  Location current = begin_;
765
0
  Location lastLineStart = current;
766
0
  line = 0;
767
0
  while (current < location && current != end_) {
768
0
    Char c = *current++;
769
0
    if (c == '\r') {
770
0
      if (*current == '\n')
771
0
        ++current;
772
0
      lastLineStart = current;
773
0
      ++line;
774
0
    } else if (c == '\n') {
775
0
      lastLineStart = current;
776
0
      ++line;
777
0
    }
778
0
  }
779
  // column & line start at 1
780
0
  column = int(location - lastLineStart) + 1;
781
0
  ++line;
782
0
}
783
784
0
String Reader::getLocationLineAndColumn(Location location) const {
785
0
  int line, column;
786
0
  getLocationLineAndColumn(location, line, column);
787
0
  char buffer[18 + 16 + 16 + 1];
788
0
  jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
789
0
  return buffer;
790
0
}
791
792
// Deprecated. Preserved for backward compatibility
793
0
String Reader::getFormatedErrorMessages() const {
794
0
  return getFormattedErrorMessages();
795
0
}
796
797
0
String Reader::getFormattedErrorMessages() const {
798
0
  String formattedMessage;
799
0
  for (const auto& error : errors_) {
800
0
    formattedMessage +=
801
0
        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
802
0
    formattedMessage += "  " + error.message_ + "\n";
803
0
    if (error.extra_)
804
0
      formattedMessage +=
805
0
          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
806
0
  }
807
0
  return formattedMessage;
808
0
}
809
810
0
std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
811
0
  std::vector<Reader::StructuredError> allErrors;
812
0
  for (const auto& error : errors_) {
813
0
    Reader::StructuredError structured;
814
0
    structured.offset_start = error.token_.start_ - begin_;
815
0
    structured.offset_limit = error.token_.end_ - begin_;
816
0
    structured.message = error.message_;
817
0
    allErrors.push_back(structured);
818
0
  }
819
0
  return allErrors;
820
0
}
821
822
0
bool Reader::pushError(const Value& value, const String& message) {
823
0
  ptrdiff_t const length = end_ - begin_;
824
0
  if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
825
0
    return false;
826
0
  Token token;
827
0
  token.type_ = tokenError;
828
0
  token.start_ = begin_ + value.getOffsetStart();
829
0
  token.end_ = begin_ + value.getOffsetLimit();
830
0
  ErrorInfo info;
831
0
  info.token_ = token;
832
0
  info.message_ = message;
833
0
  info.extra_ = nullptr;
834
0
  errors_.push_back(info);
835
0
  return true;
836
0
}
837
838
bool Reader::pushError(const Value& value, const String& message,
839
0
                       const Value& extra) {
840
0
  ptrdiff_t const length = end_ - begin_;
841
0
  if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
842
0
      extra.getOffsetLimit() > length)
843
0
    return false;
844
0
  Token token;
845
0
  token.type_ = tokenError;
846
0
  token.start_ = begin_ + value.getOffsetStart();
847
0
  token.end_ = begin_ + value.getOffsetLimit();
848
0
  ErrorInfo info;
849
0
  info.token_ = token;
850
0
  info.message_ = message;
851
0
  info.extra_ = begin_ + extra.getOffsetStart();
852
0
  errors_.push_back(info);
853
0
  return true;
854
0
}
855
856
0
bool Reader::good() const { return errors_.empty(); }
857
858
// Originally copied from the Features class (now deprecated), used internally
859
// for features implementation.
860
class OurFeatures {
861
public:
862
  static OurFeatures all();
863
  bool allowComments_;
864
  bool allowTrailingCommas_;
865
  bool strictRoot_;
866
  bool allowDroppedNullPlaceholders_;
867
  bool allowNumericKeys_;
868
  bool allowSingleQuotes_;
869
  bool failIfExtra_;
870
  bool rejectDupKeys_;
871
  bool allowSpecialFloats_;
872
  bool skipBom_;
873
  size_t stackLimit_;
874
}; // OurFeatures
875
876
25.6k
OurFeatures OurFeatures::all() { return {}; }
877
878
// Implementation of class Reader
879
// ////////////////////////////////
880
881
// Originally copied from the Reader class (now deprecated), used internally
882
// for implementing JSON reading.
883
class OurReader {
884
public:
885
  using Char = char;
886
  using Location = const Char*;
887
  struct StructuredError {
888
    ptrdiff_t offset_start;
889
    ptrdiff_t offset_limit;
890
    String message;
891
  };
892
893
  explicit OurReader(OurFeatures const& features);
894
  bool parse(const char* beginDoc, const char* endDoc, Value& root,
895
             bool collectComments = true);
896
  String getFormattedErrorMessages() const;
897
  std::vector<StructuredError> getStructuredErrors() const;
898
899
private:
900
  OurReader(OurReader const&);      // no impl
901
  void operator=(OurReader const&); // no impl
902
903
  enum TokenType {
904
    tokenEndOfStream = 0,
905
    tokenObjectBegin,
906
    tokenObjectEnd,
907
    tokenArrayBegin,
908
    tokenArrayEnd,
909
    tokenString,
910
    tokenNumber,
911
    tokenTrue,
912
    tokenFalse,
913
    tokenNull,
914
    tokenNaN,
915
    tokenPosInf,
916
    tokenNegInf,
917
    tokenArraySeparator,
918
    tokenMemberSeparator,
919
    tokenComment,
920
    tokenError
921
  };
922
923
  class Token {
924
  public:
925
    TokenType type_;
926
    Location start_;
927
    Location end_;
928
  };
929
930
  class ErrorInfo {
931
  public:
932
    Token token_;
933
    String message_;
934
    Location extra_;
935
  };
936
937
  using Errors = std::deque<ErrorInfo>;
938
939
  bool readToken(Token& token);
940
  void skipSpaces();
941
  void skipBom(bool skipBom);
942
  bool match(const Char* pattern, int patternLength);
943
  bool readComment();
944
  bool readCStyleComment(bool* containsNewLineResult);
945
  bool readCppStyleComment();
946
  bool readString();
947
  bool readStringSingleQuote();
948
  bool readNumber(bool checkInf);
949
  bool readValue();
950
  bool readObject(Token& token);
951
  bool readArray(Token& token);
952
  bool decodeNumber(Token& token);
953
  bool decodeNumber(Token& token, Value& decoded);
954
  bool decodeString(Token& token);
955
  bool decodeString(Token& token, String& decoded);
956
  bool decodeDouble(Token& token);
957
  bool decodeDouble(Token& token, Value& decoded);
958
  bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
959
                              unsigned int& unicode);
960
  bool decodeUnicodeEscapeSequence(Token& token, Location& current,
961
                                   Location end, unsigned int& unicode);
962
  bool addError(const String& message, Token& token, Location extra = nullptr);
963
  bool recoverFromError(TokenType skipUntilToken);
964
  bool addErrorAndRecover(const String& message, Token& token,
965
                          TokenType skipUntilToken);
966
  void skipUntilSpace();
967
  Value& currentValue();
968
  Char getNextChar();
969
  void getLocationLineAndColumn(Location location, int& line,
970
                                int& column) const;
971
  String getLocationLineAndColumn(Location location) const;
972
  void addComment(Location begin, Location end, CommentPlacement placement);
973
  void skipCommentTokens(Token& token);
974
975
  static String normalizeEOL(Location begin, Location end);
976
  static bool containsNewLine(Location begin, Location end);
977
978
  using Nodes = std::stack<Value*>;
979
980
  Nodes nodes_{};
981
  Errors errors_{};
982
  String document_{};
983
  Location begin_ = nullptr;
984
  Location end_ = nullptr;
985
  Location current_ = nullptr;
986
  Location lastValueEnd_ = nullptr;
987
  Value* lastValue_ = nullptr;
988
  bool lastValueHasAComment_ = false;
989
  String commentsBefore_{};
990
991
  OurFeatures const features_;
992
  bool collectComments_ = false;
993
}; // OurReader
994
995
// complete copy of Read impl, for OurReader
996
997
bool OurReader::containsNewLine(OurReader::Location begin,
998
3.41k
                                OurReader::Location end) {
999
6.98k
  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
1000
3.41k
}
1001
1002
25.6k
OurReader::OurReader(OurFeatures const& features) : features_(features) {}
1003
1004
bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
1005
25.6k
                      bool collectComments) {
1006
25.6k
  if (!features_.allowComments_) {
1007
0
    collectComments = false;
1008
0
  }
1009
1010
25.6k
  begin_ = beginDoc;
1011
25.6k
  end_ = endDoc;
1012
25.6k
  collectComments_ = collectComments;
1013
25.6k
  current_ = begin_;
1014
25.6k
  lastValueEnd_ = nullptr;
1015
25.6k
  lastValue_ = nullptr;
1016
25.6k
  commentsBefore_.clear();
1017
25.6k
  errors_.clear();
1018
25.6k
  while (!nodes_.empty())
1019
0
    nodes_.pop();
1020
25.6k
  nodes_.push(&root);
1021
1022
  // skip byte order mark if it exists at the beginning of the UTF-8 text.
1023
25.6k
  skipBom(features_.skipBom_);
1024
25.6k
  bool successful = readValue();
1025
25.6k
  nodes_.pop();
1026
25.6k
  Token token;
1027
25.6k
  skipCommentTokens(token);
1028
25.6k
  if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
1029
0
    addError("Extra non-whitespace after JSON value.", token);
1030
0
    return false;
1031
0
  }
1032
25.6k
  if (collectComments_ && !commentsBefore_.empty())
1033
2.24k
    root.setComment(commentsBefore_, commentAfter);
1034
25.6k
  if (features_.strictRoot_) {
1035
0
    if (!root.isArray() && !root.isObject()) {
1036
      // Set error location to start of doc, ideally should be first token found
1037
      // in doc
1038
0
      token.type_ = tokenError;
1039
0
      token.start_ = beginDoc;
1040
0
      token.end_ = endDoc;
1041
0
      addError(
1042
0
          "A valid JSON document must be either an array or an object value.",
1043
0
          token);
1044
0
      return false;
1045
0
    }
1046
0
  }
1047
25.6k
  return successful;
1048
25.6k
}
1049
1050
58.2k
bool OurReader::readValue() {
1051
  //  To preserve the old behaviour we cast size_t to int.
1052
58.2k
  if (nodes_.size() > features_.stackLimit_)
1053
0
    throwRuntimeError("Exceeded stackLimit in readValue().");
1054
58.2k
  Token token;
1055
58.2k
  skipCommentTokens(token);
1056
58.2k
  bool successful = true;
1057
1058
58.2k
  if (collectComments_ && !commentsBefore_.empty()) {
1059
583
    currentValue().setComment(commentsBefore_, commentBefore);
1060
583
    commentsBefore_.clear();
1061
583
  }
1062
1063
58.2k
  switch (token.type_) {
1064
6.20k
  case tokenObjectBegin:
1065
6.20k
    successful = readObject(token);
1066
6.20k
    currentValue().setOffsetLimit(current_ - begin_);
1067
6.20k
    break;
1068
19.7k
  case tokenArrayBegin:
1069
19.7k
    successful = readArray(token);
1070
19.7k
    currentValue().setOffsetLimit(current_ - begin_);
1071
19.7k
    break;
1072
24.4k
  case tokenNumber:
1073
24.4k
    successful = decodeNumber(token);
1074
24.4k
    break;
1075
2.63k
  case tokenString:
1076
2.63k
    successful = decodeString(token);
1077
2.63k
    break;
1078
0
  case tokenTrue: {
1079
0
    Value v(true);
1080
0
    currentValue().swapPayload(v);
1081
0
    currentValue().setOffsetStart(token.start_ - begin_);
1082
0
    currentValue().setOffsetLimit(token.end_ - begin_);
1083
0
  } break;
1084
0
  case tokenFalse: {
1085
0
    Value v(false);
1086
0
    currentValue().swapPayload(v);
1087
0
    currentValue().setOffsetStart(token.start_ - begin_);
1088
0
    currentValue().setOffsetLimit(token.end_ - begin_);
1089
0
  } break;
1090
0
  case tokenNull: {
1091
0
    Value v;
1092
0
    currentValue().swapPayload(v);
1093
0
    currentValue().setOffsetStart(token.start_ - begin_);
1094
0
    currentValue().setOffsetLimit(token.end_ - begin_);
1095
0
  } break;
1096
0
  case tokenNaN: {
1097
0
    Value v(std::numeric_limits<double>::quiet_NaN());
1098
0
    currentValue().swapPayload(v);
1099
0
    currentValue().setOffsetStart(token.start_ - begin_);
1100
0
    currentValue().setOffsetLimit(token.end_ - begin_);
1101
0
  } break;
1102
0
  case tokenPosInf: {
1103
0
    Value v(std::numeric_limits<double>::infinity());
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 tokenNegInf: {
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
806
  case tokenArraySeparator:
1115
2.14k
  case tokenObjectEnd:
1116
2.14k
  case tokenArrayEnd:
1117
2.14k
    if (features_.allowDroppedNullPlaceholders_) {
1118
      // "Un-read" the current token and mark the current value as a null
1119
      // token.
1120
0
      current_--;
1121
0
      Value v;
1122
0
      currentValue().swapPayload(v);
1123
0
      currentValue().setOffsetStart(current_ - begin_ - 1);
1124
0
      currentValue().setOffsetLimit(current_ - begin_);
1125
0
      break;
1126
0
    } // else, fall through ...
1127
5.25k
  default:
1128
5.25k
    currentValue().setOffsetStart(token.start_ - begin_);
1129
5.25k
    currentValue().setOffsetLimit(token.end_ - begin_);
1130
5.25k
    return addError("Syntax error: value, object or array expected.", token);
1131
58.2k
  }
1132
1133
52.9k
  if (collectComments_) {
1134
52.9k
    lastValueEnd_ = current_;
1135
52.9k
    lastValueHasAComment_ = false;
1136
52.9k
    lastValue_ = &currentValue();
1137
52.9k
  }
1138
1139
52.9k
  return successful;
1140
58.2k
}
1141
1142
83.8k
void OurReader::skipCommentTokens(Token& token) {
1143
83.8k
  if (features_.allowComments_) {
1144
88.9k
    do {
1145
88.9k
      readToken(token);
1146
88.9k
    } while (token.type_ == tokenComment);
1147
83.8k
  } else {
1148
0
    readToken(token);
1149
0
  }
1150
83.8k
}
1151
1152
226k
bool OurReader::readToken(Token& token) {
1153
226k
  skipSpaces();
1154
226k
  token.start_ = current_;
1155
226k
  Char c = getNextChar();
1156
226k
  bool ok = true;
1157
226k
  switch (c) {
1158
6.58k
  case '{':
1159
6.58k
    token.type_ = tokenObjectBegin;
1160
6.58k
    break;
1161
8.14k
  case '}':
1162
8.14k
    token.type_ = tokenObjectEnd;
1163
8.14k
    break;
1164
21.2k
  case '[':
1165
21.2k
    token.type_ = tokenArrayBegin;
1166
21.2k
    break;
1167
7.41k
  case ']':
1168
7.41k
    token.type_ = tokenArrayEnd;
1169
7.41k
    break;
1170
10.3k
  case '"':
1171
10.3k
    token.type_ = tokenString;
1172
10.3k
    ok = readString();
1173
10.3k
    break;
1174
55
  case '\'':
1175
55
    if (features_.allowSingleQuotes_) {
1176
0
      token.type_ = tokenString;
1177
0
      ok = readStringSingleQuote();
1178
0
      break;
1179
0
    } // else fall through
1180
6.92k
  case '/':
1181
6.92k
    token.type_ = tokenComment;
1182
6.92k
    ok = readComment();
1183
6.92k
    break;
1184
830
  case '0':
1185
8.07k
  case '1':
1186
10.7k
  case '2':
1187
12.7k
  case '3':
1188
13.1k
  case '4':
1189
16.2k
  case '5':
1190
20.7k
  case '6':
1191
20.8k
  case '7':
1192
24.8k
  case '8':
1193
34.0k
  case '9':
1194
34.0k
    token.type_ = tokenNumber;
1195
34.0k
    readNumber(false);
1196
34.0k
    break;
1197
3.50k
  case '-':
1198
3.50k
    if (readNumber(true)) {
1199
2.53k
      token.type_ = tokenNumber;
1200
2.53k
    } else {
1201
973
      token.type_ = tokenNegInf;
1202
973
      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1203
973
    }
1204
3.50k
    break;
1205
9.22k
  case '+':
1206
9.22k
    if (readNumber(true)) {
1207
8.11k
      token.type_ = tokenNumber;
1208
8.11k
    } else {
1209
1.10k
      token.type_ = tokenPosInf;
1210
1.10k
      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1211
1.10k
    }
1212
9.22k
    break;
1213
802
  case 't':
1214
802
    token.type_ = tokenTrue;
1215
802
    ok = match("rue", 3);
1216
802
    break;
1217
1.95k
  case 'f':
1218
1.95k
    token.type_ = tokenFalse;
1219
1.95k
    ok = match("alse", 4);
1220
1.95k
    break;
1221
67
  case 'n':
1222
67
    token.type_ = tokenNull;
1223
67
    ok = match("ull", 3);
1224
67
    break;
1225
4
  case 'N':
1226
4
    if (features_.allowSpecialFloats_) {
1227
0
      token.type_ = tokenNaN;
1228
0
      ok = match("aN", 2);
1229
4
    } else {
1230
4
      ok = false;
1231
4
    }
1232
4
    break;
1233
35.2k
  case 'I':
1234
35.2k
    if (features_.allowSpecialFloats_) {
1235
0
      token.type_ = tokenPosInf;
1236
0
      ok = match("nfinity", 7);
1237
35.2k
    } else {
1238
35.2k
      ok = false;
1239
35.2k
    }
1240
35.2k
    break;
1241
11.0k
  case ',':
1242
11.0k
    token.type_ = tokenArraySeparator;
1243
11.0k
    break;
1244
4.32k
  case ':':
1245
4.32k
    token.type_ = tokenMemberSeparator;
1246
4.32k
    break;
1247
34.0k
  case 0:
1248
34.0k
    token.type_ = tokenEndOfStream;
1249
34.0k
    break;
1250
31.2k
  default:
1251
31.2k
    ok = false;
1252
31.2k
    break;
1253
226k
  }
1254
226k
  if (!ok)
1255
75.3k
    token.type_ = tokenError;
1256
226k
  token.end_ = current_;
1257
226k
  return ok;
1258
226k
}
1259
1260
254k
void OurReader::skipSpaces() {
1261
255k
  while (current_ != end_) {
1262
224k
    Char c = *current_;
1263
224k
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1264
897
      ++current_;
1265
223k
    else
1266
223k
      break;
1267
224k
  }
1268
254k
}
1269
1270
25.6k
void OurReader::skipBom(bool skipBom) {
1271
  // The default behavior is to skip BOM.
1272
25.6k
  if (skipBom) {
1273
25.6k
    if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
1274
222
      begin_ += 3;
1275
222
      current_ = begin_;
1276
222
    }
1277
25.6k
  }
1278
25.6k
}
1279
1280
2.82k
bool OurReader::match(const Char* pattern, int patternLength) {
1281
2.82k
  if (end_ - current_ < patternLength)
1282
126
    return false;
1283
2.69k
  int index = patternLength;
1284
3.11k
  while (index--)
1285
3.11k
    if (current_[index] != pattern[index])
1286
2.69k
      return false;
1287
0
  current_ += patternLength;
1288
0
  return true;
1289
2.69k
}
1290
1291
6.92k
bool OurReader::readComment() {
1292
6.92k
  const Location commentBegin = current_ - 1;
1293
6.92k
  const Char c = getNextChar();
1294
6.92k
  bool successful = false;
1295
6.92k
  bool cStyleWithEmbeddedNewline = false;
1296
1297
6.92k
  const bool isCStyleComment = (c == '*');
1298
6.92k
  const bool isCppStyleComment = (c == '/');
1299
6.92k
  if (isCStyleComment) {
1300
4.01k
    successful = readCStyleComment(&cStyleWithEmbeddedNewline);
1301
4.01k
  } else if (isCppStyleComment) {
1302
2.28k
    successful = readCppStyleComment();
1303
2.28k
  }
1304
1305
6.92k
  if (!successful)
1306
1.81k
    return false;
1307
1308
5.11k
  if (collectComments_) {
1309
5.11k
    CommentPlacement placement = commentBefore;
1310
1311
5.11k
    if (!lastValueHasAComment_) {
1312
4.03k
      if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1313
2.25k
        if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
1314
1.08k
          placement = commentAfterOnSameLine;
1315
1.08k
          lastValueHasAComment_ = true;
1316
1.08k
        }
1317
2.25k
      }
1318
4.03k
    }
1319
1320
5.11k
    addComment(commentBegin, current_, placement);
1321
5.11k
  }
1322
5.11k
  return true;
1323
6.92k
}
1324
1325
String OurReader::normalizeEOL(OurReader::Location begin,
1326
5.11k
                               OurReader::Location end) {
1327
5.11k
  String normalized;
1328
5.11k
  normalized.reserve(static_cast<size_t>(end - begin));
1329
5.11k
  OurReader::Location current = begin;
1330
40.6k
  while (current != end) {
1331
35.5k
    char c = *current++;
1332
35.5k
    if (c == '\r') {
1333
619
      if (current != end && *current == '\n')
1334
        // convert dos EOL
1335
547
        ++current;
1336
      // convert Mac EOL
1337
619
      normalized += '\n';
1338
34.9k
    } else {
1339
34.9k
      normalized += c;
1340
34.9k
    }
1341
35.5k
  }
1342
5.11k
  return normalized;
1343
5.11k
}
1344
1345
void OurReader::addComment(Location begin, Location end,
1346
5.11k
                           CommentPlacement placement) {
1347
5.11k
  assert(collectComments_);
1348
5.11k
  const String& normalized = normalizeEOL(begin, end);
1349
5.11k
  if (placement == commentAfterOnSameLine) {
1350
1.08k
    assert(lastValue_ != nullptr);
1351
1.08k
    lastValue_->setComment(normalized, placement);
1352
4.02k
  } else {
1353
4.02k
    commentsBefore_ += normalized;
1354
4.02k
  }
1355
5.11k
}
1356
1357
4.01k
bool OurReader::readCStyleComment(bool* containsNewLineResult) {
1358
4.01k
  *containsNewLineResult = false;
1359
1360
34.6k
  while ((current_ + 1) < end_) {
1361
33.4k
    Char c = getNextChar();
1362
33.4k
    if (c == '*' && *current_ == '/')
1363
2.82k
      break;
1364
30.6k
    if (c == '\n')
1365
2.65k
      *containsNewLineResult = true;
1366
30.6k
  }
1367
1368
4.01k
  return getNextChar() == '/';
1369
4.01k
}
1370
1371
2.28k
bool OurReader::readCppStyleComment() {
1372
5.41k
  while (current_ != end_) {
1373
3.96k
    Char c = getNextChar();
1374
3.96k
    if (c == '\n')
1375
791
      break;
1376
3.17k
    if (c == '\r') {
1377
      // Consume DOS EOL. It will be normalized in addComment.
1378
43
      if (current_ != end_ && *current_ == '\n')
1379
11
        getNextChar();
1380
      // Break on Moc OS 9 EOL.
1381
43
      break;
1382
43
    }
1383
3.17k
  }
1384
2.28k
  return true;
1385
2.28k
}
1386
1387
46.7k
bool OurReader::readNumber(bool checkInf) {
1388
46.7k
  Location p = current_;
1389
46.7k
  if (checkInf && p != end_ && *p == 'I') {
1390
2.08k
    current_ = ++p;
1391
2.08k
    return false;
1392
2.08k
  }
1393
44.6k
  char c = '0'; // stopgap for already consumed character
1394
  // integral part
1395
143k
  while (c >= '0' && c <= '9')
1396
98.5k
    c = (current_ = p) < end_ ? *p++ : '\0';
1397
  // fractional part
1398
44.6k
  if (c == '.') {
1399
437
    c = (current_ = p) < end_ ? *p++ : '\0';
1400
799
    while (c >= '0' && c <= '9')
1401
362
      c = (current_ = p) < end_ ? *p++ : '\0';
1402
437
  }
1403
  // exponential part
1404
44.6k
  if (c == 'e' || c == 'E') {
1405
7.92k
    c = (current_ = p) < end_ ? *p++ : '\0';
1406
7.92k
    if (c == '+' || c == '-')
1407
1.06k
      c = (current_ = p) < end_ ? *p++ : '\0';
1408
19.3k
    while (c >= '0' && c <= '9')
1409
11.4k
      c = (current_ = p) < end_ ? *p++ : '\0';
1410
7.92k
  }
1411
44.6k
  return true;
1412
46.7k
}
1413
10.3k
bool OurReader::readString() {
1414
10.3k
  Char c = 0;
1415
46.7k
  while (current_ != end_) {
1416
44.6k
    c = getNextChar();
1417
44.6k
    if (c == '\\')
1418
5.99k
      getNextChar();
1419
38.6k
    else if (c == '"')
1420
8.20k
      break;
1421
44.6k
  }
1422
10.3k
  return c == '"';
1423
10.3k
}
1424
1425
0
bool OurReader::readStringSingleQuote() {
1426
0
  Char c = 0;
1427
0
  while (current_ != end_) {
1428
0
    c = getNextChar();
1429
0
    if (c == '\\')
1430
0
      getNextChar();
1431
0
    else if (c == '\'')
1432
0
      break;
1433
0
  }
1434
0
  return c == '\'';
1435
0
}
1436
1437
6.20k
bool OurReader::readObject(Token& token) {
1438
6.20k
  Token tokenName;
1439
6.20k
  String name;
1440
6.20k
  Value init(objectValue);
1441
6.20k
  currentValue().swapPayload(init);
1442
6.20k
  currentValue().setOffsetStart(token.start_ - begin_);
1443
6.39k
  while (readToken(tokenName)) {
1444
5.76k
    bool initialTokenOk = true;
1445
5.76k
    while (tokenName.type_ == tokenComment && initialTokenOk)
1446
0
      initialTokenOk = readToken(tokenName);
1447
5.76k
    if (!initialTokenOk)
1448
0
      break;
1449
5.76k
    if (tokenName.type_ == tokenObjectEnd &&
1450
5.76k
        (name.empty() ||
1451
561
         features_.allowTrailingCommas_)) // empty object or trailing comma
1452
561
      return true;
1453
5.20k
    name.clear();
1454
5.20k
    if (tokenName.type_ == tokenString) {
1455
4.96k
      if (!decodeString(tokenName, name))
1456
180
        return recoverFromError(tokenObjectEnd);
1457
4.96k
    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
1458
0
      Value numberName;
1459
0
      if (!decodeNumber(tokenName, numberName))
1460
0
        return recoverFromError(tokenObjectEnd);
1461
0
      name = numberName.asString();
1462
238
    } else {
1463
238
      break;
1464
238
    }
1465
4.78k
    if (name.length() >= (1U << 30))
1466
0
      throwRuntimeError("keylength >= 2^30");
1467
4.78k
    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1468
0
      String msg = "Duplicate key: '" + name + "'";
1469
0
      return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1470
0
    }
1471
1472
4.78k
    Token colon;
1473
4.78k
    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1474
852
      return addErrorAndRecover("Missing ':' after object member name", colon,
1475
852
                                tokenObjectEnd);
1476
852
    }
1477
3.93k
    Value& value = currentValue()[name];
1478
3.93k
    nodes_.push(&value);
1479
3.93k
    bool ok = readValue();
1480
3.93k
    nodes_.pop();
1481
3.93k
    if (!ok) // error already set
1482
2.32k
      return recoverFromError(tokenObjectEnd);
1483
1484
1.60k
    Token comma;
1485
1.60k
    if (!readToken(comma) ||
1486
1.60k
        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1487
995
         comma.type_ != tokenComment)) {
1488
713
      return addErrorAndRecover("Missing ',' or '}' in object declaration",
1489
713
                                comma, tokenObjectEnd);
1490
713
    }
1491
896
    bool finalizeTokenOk = true;
1492
896
    while (comma.type_ == tokenComment && finalizeTokenOk)
1493
0
      finalizeTokenOk = readToken(comma);
1494
896
    if (comma.type_ == tokenObjectEnd)
1495
704
      return true;
1496
896
  }
1497
867
  return addErrorAndRecover("Missing '}' or object member name", tokenName,
1498
867
                            tokenObjectEnd);
1499
6.20k
}
1500
1501
19.7k
bool OurReader::readArray(Token& token) {
1502
19.7k
  Value init(arrayValue);
1503
19.7k
  currentValue().swapPayload(init);
1504
19.7k
  currentValue().setOffsetStart(token.start_ - begin_);
1505
19.7k
  int index = 0;
1506
28.7k
  for (;;) {
1507
28.7k
    skipSpaces();
1508
28.7k
    if (current_ != end_ && *current_ == ']' &&
1509
28.7k
        (index == 0 ||
1510
59
         (features_.allowTrailingCommas_ &&
1511
57
          !features_.allowDroppedNullPlaceholders_))) // empty array or trailing
1512
                                                      // comma
1513
59
    {
1514
59
      Token endArray;
1515
59
      readToken(endArray);
1516
59
      return true;
1517
59
    }
1518
28.6k
    Value& value = currentValue()[index++];
1519
28.6k
    nodes_.push(&value);
1520
28.6k
    bool ok = readValue();
1521
28.6k
    nodes_.pop();
1522
28.6k
    if (!ok) // error already set
1523
10.8k
      return recoverFromError(tokenArrayEnd);
1524
1525
17.8k
    Token currentToken;
1526
    // Accept Comment after last item in the array.
1527
17.8k
    ok = readToken(currentToken);
1528
17.8k
    while (currentToken.type_ == tokenComment && ok) {
1529
2
      ok = readToken(currentToken);
1530
2
    }
1531
17.8k
    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
1532
17.8k
                         currentToken.type_ != tokenArrayEnd);
1533
17.8k
    if (!ok || badTokenType) {
1534
3.79k
      return addErrorAndRecover("Missing ',' or ']' in array declaration",
1535
3.79k
                                currentToken, tokenArrayEnd);
1536
3.79k
    }
1537
14.0k
    if (currentToken.type_ == tokenArrayEnd)
1538
5.04k
      break;
1539
14.0k
  }
1540
5.04k
  return true;
1541
19.7k
}
1542
1543
24.4k
bool OurReader::decodeNumber(Token& token) {
1544
24.4k
  Value decoded;
1545
24.4k
  if (!decodeNumber(token, decoded))
1546
5.77k
    return false;
1547
18.6k
  currentValue().swapPayload(decoded);
1548
18.6k
  currentValue().setOffsetStart(token.start_ - begin_);
1549
18.6k
  currentValue().setOffsetLimit(token.end_ - begin_);
1550
18.6k
  return true;
1551
24.4k
}
1552
1553
24.4k
bool OurReader::decodeNumber(Token& token, Value& decoded) {
1554
  // Attempts to parse the number as an integer. If the number is
1555
  // larger than the maximum supported value of an integer then
1556
  // we decode the number as a double.
1557
24.4k
  Location current = token.start_;
1558
24.4k
  const bool isNegative = *current == '-';
1559
24.4k
  if (isNegative) {
1560
845
    ++current;
1561
845
  }
1562
1563
  // We assume we can represent the largest and smallest integer types as
1564
  // unsigned integers with separate sign. This is only true if they can fit
1565
  // into an unsigned integer.
1566
24.4k
  static_assert(Value::maxLargestInt <= Value::maxLargestUInt,
1567
24.4k
                "Int must be smaller than UInt");
1568
1569
  // We need to convert minLargestInt into a positive number. The easiest way
1570
  // to do this conversion is to assume our "threshold" value of minLargestInt
1571
  // divided by 10 can fit in maxLargestInt when absolute valued. This should
1572
  // be a safe assumption.
1573
24.4k
  static_assert(Value::minLargestInt <= -Value::maxLargestInt,
1574
24.4k
                "The absolute value of minLargestInt must be greater than or "
1575
24.4k
                "equal to maxLargestInt");
1576
24.4k
  static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,
1577
24.4k
                "The absolute value of minLargestInt must be only 1 magnitude "
1578
24.4k
                "larger than maxLargest Int");
1579
1580
24.4k
  static constexpr Value::LargestUInt positive_threshold =
1581
24.4k
      Value::maxLargestUInt / 10;
1582
24.4k
  static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10;
1583
1584
  // For the negative values, we have to be more careful. Since typically
1585
  // -Value::minLargestInt will cause an overflow, we first divide by 10 and
1586
  // then take the inverse. This assumes that minLargestInt is only a single
1587
  // power of 10 different in magnitude, which we check above. For the last
1588
  // digit, we take the modulus before negating for the same reason.
1589
24.4k
  static constexpr auto negative_threshold =
1590
24.4k
      Value::LargestUInt(-(Value::minLargestInt / 10));
1591
24.4k
  static constexpr auto negative_last_digit =
1592
24.4k
      Value::UInt(-(Value::minLargestInt % 10));
1593
1594
24.4k
  const Value::LargestUInt threshold =
1595
24.4k
      isNegative ? negative_threshold : positive_threshold;
1596
24.4k
  const Value::UInt max_last_digit =
1597
24.4k
      isNegative ? negative_last_digit : positive_last_digit;
1598
1599
24.4k
  Value::LargestUInt value = 0;
1600
84.2k
  while (current < token.end_) {
1601
66.6k
    Char c = *current++;
1602
66.6k
    if (c < '0' || c > '9')
1603
6.83k
      return decodeDouble(token, decoded);
1604
1605
59.8k
    const auto digit(static_cast<Value::UInt>(c - '0'));
1606
59.8k
    if (value >= threshold) {
1607
      // We've hit or exceeded the max value divided by 10 (rounded down). If
1608
      // a) we've only just touched the limit, meaing value == threshold,
1609
      // b) this is the last digit, or
1610
      // c) it's small enough to fit in that rounding delta, we're okay.
1611
      // Otherwise treat this number as a double to avoid overflow.
1612
0
      if (value > threshold || current != token.end_ ||
1613
0
          digit > max_last_digit) {
1614
0
        return decodeDouble(token, decoded);
1615
0
      }
1616
0
    }
1617
59.8k
    value = value * 10 + digit;
1618
59.8k
  }
1619
1620
17.5k
  if (isNegative) {
1621
    // We use the same magnitude assumption here, just in case.
1622
169
    const auto last_digit = static_cast<Value::UInt>(value % 10);
1623
169
    decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
1624
17.4k
  } else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
1625
17.4k
    decoded = Value::LargestInt(value);
1626
17.4k
  } else {
1627
0
    decoded = value;
1628
0
  }
1629
1630
17.5k
  return true;
1631
24.4k
}
1632
1633
0
bool OurReader::decodeDouble(Token& token) {
1634
0
  Value decoded;
1635
0
  if (!decodeDouble(token, decoded))
1636
0
    return false;
1637
0
  currentValue().swapPayload(decoded);
1638
0
  currentValue().setOffsetStart(token.start_ - begin_);
1639
0
  currentValue().setOffsetLimit(token.end_ - begin_);
1640
0
  return true;
1641
0
}
1642
1643
6.83k
bool OurReader::decodeDouble(Token& token, Value& decoded) {
1644
6.83k
  double value = 0;
1645
6.83k
  const String buffer(token.start_, token.end_);
1646
6.83k
  IStringStream is(buffer);
1647
6.83k
  if (!(is >> value)) {
1648
5.77k
    return addError(
1649
5.77k
        "'" + String(token.start_, token.end_) + "' is not a number.", token);
1650
5.77k
  }
1651
1.06k
  decoded = value;
1652
1.06k
  return true;
1653
6.83k
}
1654
1655
2.63k
bool OurReader::decodeString(Token& token) {
1656
2.63k
  String decoded_string;
1657
2.63k
  if (!decodeString(token, decoded_string))
1658
902
    return false;
1659
1.73k
  Value decoded(decoded_string);
1660
1.73k
  currentValue().swapPayload(decoded);
1661
1.73k
  currentValue().setOffsetStart(token.start_ - begin_);
1662
1.73k
  currentValue().setOffsetLimit(token.end_ - begin_);
1663
1.73k
  return true;
1664
2.63k
}
1665
1666
7.60k
bool OurReader::decodeString(Token& token, String& decoded) {
1667
7.60k
  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1668
7.60k
  Location current = token.start_ + 1; // skip '"'
1669
7.60k
  Location end = token.end_ - 1;       // do not include '"'
1670
22.1k
  while (current != end) {
1671
15.6k
    Char c = *current++;
1672
15.6k
    if (c == '"')
1673
0
      break;
1674
15.6k
    if (c == '\\') {
1675
2.27k
      if (current == end)
1676
0
        return addError("Empty escape sequence in string", token, current);
1677
2.27k
      Char escape = *current++;
1678
2.27k
      switch (escape) {
1679
0
      case '"':
1680
0
        decoded += '"';
1681
0
        break;
1682
7
      case '/':
1683
7
        decoded += '/';
1684
7
        break;
1685
866
      case '\\':
1686
866
        decoded += '\\';
1687
866
        break;
1688
1
      case 'b':
1689
1
        decoded += '\b';
1690
1
        break;
1691
0
      case 'f':
1692
0
        decoded += '\f';
1693
0
        break;
1694
1
      case 'n':
1695
1
        decoded += '\n';
1696
1
        break;
1697
1
      case 'r':
1698
1
        decoded += '\r';
1699
1
        break;
1700
1
      case 't':
1701
1
        decoded += '\t';
1702
1
        break;
1703
1.18k
      case 'u': {
1704
1.18k
        unsigned int unicode;
1705
1.18k
        if (!decodeUnicodeCodePoint(token, current, end, unicode))
1706
867
          return false;
1707
315
        decoded += codePointToUTF8(unicode);
1708
315
      } break;
1709
215
      default:
1710
215
        return addError("Bad escape sequence in string", token, current);
1711
2.27k
      }
1712
13.3k
    } else {
1713
13.3k
      decoded += c;
1714
13.3k
    }
1715
15.6k
  }
1716
6.52k
  return true;
1717
7.60k
}
1718
1719
bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
1720
1.18k
                                       Location end, unsigned int& unicode) {
1721
1722
1.18k
  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1723
867
    return false;
1724
315
  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
1725
    // surrogate pairs
1726
0
    if (end - current < 6)
1727
0
      return addError(
1728
0
          "additional six characters expected to parse unicode surrogate pair.",
1729
0
          token, current);
1730
0
    if (*(current++) == '\\' && *(current++) == 'u') {
1731
0
      unsigned int surrogatePair;
1732
0
      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
1733
0
        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
1734
0
      } else
1735
0
        return false;
1736
0
    } else
1737
0
      return addError("expecting another \\u token to begin the second half of "
1738
0
                      "a unicode surrogate pair",
1739
0
                      token, current);
1740
0
  }
1741
315
  return true;
1742
315
}
1743
1744
bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
1745
                                            Location end,
1746
1.18k
                                            unsigned int& ret_unicode) {
1747
1.18k
  if (end - current < 4)
1748
1
    return addError(
1749
1
        "Bad unicode escape sequence in string: four digits expected.", token,
1750
1
        current);
1751
1.18k
  int unicode = 0;
1752
3.53k
  for (int index = 0; index < 4; ++index) {
1753
3.22k
    Char c = *current++;
1754
3.22k
    unicode *= 16;
1755
3.22k
    if (c >= '0' && c <= '9')
1756
76
      unicode += c - '0';
1757
3.14k
    else if (c >= 'a' && c <= 'f')
1758
672
      unicode += c - 'a' + 10;
1759
2.47k
    else if (c >= 'A' && c <= 'F')
1760
1.60k
      unicode += c - 'A' + 10;
1761
866
    else
1762
866
      return addError(
1763
866
          "Bad unicode escape sequence in string: hexadecimal digit expected.",
1764
866
          token, current);
1765
3.22k
  }
1766
315
  ret_unicode = static_cast<unsigned int>(unicode);
1767
315
  return true;
1768
1.18k
}
1769
1770
18.3k
bool OurReader::addError(const String& message, Token& token, Location extra) {
1771
18.3k
  ErrorInfo info;
1772
18.3k
  info.token_ = token;
1773
18.3k
  info.message_ = message;
1774
18.3k
  info.extra_ = extra;
1775
18.3k
  errors_.push_back(info);
1776
18.3k
  return false;
1777
18.3k
}
1778
1779
19.5k
bool OurReader::recoverFromError(TokenType skipUntilToken) {
1780
19.5k
  size_t errorCount = errors_.size();
1781
19.5k
  Token skip;
1782
106k
  for (;;) {
1783
106k
    if (!readToken(skip))
1784
66.4k
      errors_.resize(errorCount); // discard errors caused by recovery
1785
106k
    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1786
19.5k
      break;
1787
106k
  }
1788
19.5k
  errors_.resize(errorCount);
1789
19.5k
  return false;
1790
19.5k
}
1791
1792
bool OurReader::addErrorAndRecover(const String& message, Token& token,
1793
6.23k
                                   TokenType skipUntilToken) {
1794
6.23k
  addError(message, token);
1795
6.23k
  return recoverFromError(skipUntilToken);
1796
6.23k
}
1797
1798
235k
Value& OurReader::currentValue() { return *(nodes_.top()); }
1799
1800
325k
OurReader::Char OurReader::getNextChar() {
1801
325k
  if (current_ == end_)
1802
31.2k
    return 0;
1803
293k
  return *current_++;
1804
325k
}
1805
1806
void OurReader::getLocationLineAndColumn(Location location, int& line,
1807
0
                                         int& column) const {
1808
0
  Location current = begin_;
1809
0
  Location lastLineStart = current;
1810
0
  line = 0;
1811
0
  while (current < location && current != end_) {
1812
0
    Char c = *current++;
1813
0
    if (c == '\r') {
1814
0
      if (*current == '\n')
1815
0
        ++current;
1816
0
      lastLineStart = current;
1817
0
      ++line;
1818
0
    } else if (c == '\n') {
1819
0
      lastLineStart = current;
1820
0
      ++line;
1821
0
    }
1822
0
  }
1823
  // column & line start at 1
1824
0
  column = int(location - lastLineStart) + 1;
1825
0
  ++line;
1826
0
}
1827
1828
0
String OurReader::getLocationLineAndColumn(Location location) const {
1829
0
  int line, column;
1830
0
  getLocationLineAndColumn(location, line, column);
1831
0
  char buffer[18 + 16 + 16 + 1];
1832
0
  jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
1833
0
  return buffer;
1834
0
}
1835
1836
0
String OurReader::getFormattedErrorMessages() const {
1837
0
  String formattedMessage;
1838
0
  for (const auto& error : errors_) {
1839
0
    formattedMessage +=
1840
0
        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
1841
0
    formattedMessage += "  " + error.message_ + "\n";
1842
0
    if (error.extra_)
1843
0
      formattedMessage +=
1844
0
          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
1845
0
  }
1846
0
  return formattedMessage;
1847
0
}
1848
1849
0
std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
1850
0
  std::vector<OurReader::StructuredError> allErrors;
1851
0
  for (const auto& error : errors_) {
1852
0
    OurReader::StructuredError structured;
1853
0
    structured.offset_start = error.token_.start_ - begin_;
1854
0
    structured.offset_limit = error.token_.end_ - begin_;
1855
0
    structured.message = error.message_;
1856
0
    allErrors.push_back(structured);
1857
0
  }
1858
0
  return allErrors;
1859
0
}
1860
1861
class OurCharReader : public CharReader {
1862
  bool const collectComments_;
1863
  OurReader reader_;
1864
1865
public:
1866
  OurCharReader(bool collectComments, OurFeatures const& features)
1867
25.6k
      : collectComments_(collectComments), reader_(features) {}
1868
  bool parse(char const* beginDoc, char const* endDoc, Value* root,
1869
25.6k
             String* errs) override {
1870
25.6k
    bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1871
25.6k
    if (errs) {
1872
0
      *errs = reader_.getFormattedErrorMessages();
1873
0
    }
1874
25.6k
    return ok;
1875
25.6k
  }
1876
};
1877
1878
25.6k
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
1879
25.6k
CharReaderBuilder::~CharReaderBuilder() = default;
1880
25.6k
CharReader* CharReaderBuilder::newCharReader() const {
1881
25.6k
  bool collectComments = settings_["collectComments"].asBool();
1882
25.6k
  OurFeatures features = OurFeatures::all();
1883
25.6k
  features.allowComments_ = settings_["allowComments"].asBool();
1884
25.6k
  features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
1885
25.6k
  features.strictRoot_ = settings_["strictRoot"].asBool();
1886
25.6k
  features.allowDroppedNullPlaceholders_ =
1887
25.6k
      settings_["allowDroppedNullPlaceholders"].asBool();
1888
25.6k
  features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
1889
25.6k
  features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
1890
1891
  // Stack limit is always a size_t, so we get this as an unsigned int
1892
  // regardless of it we have 64-bit integer support enabled.
1893
25.6k
  features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());
1894
25.6k
  features.failIfExtra_ = settings_["failIfExtra"].asBool();
1895
25.6k
  features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
1896
25.6k
  features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
1897
25.6k
  features.skipBom_ = settings_["skipBom"].asBool();
1898
25.6k
  return new OurCharReader(collectComments, features);
1899
25.6k
}
1900
1901
0
bool CharReaderBuilder::validate(Json::Value* invalid) const {
1902
0
  static const auto& valid_keys = *new std::set<String>{
1903
0
      "collectComments",
1904
0
      "allowComments",
1905
0
      "allowTrailingCommas",
1906
0
      "strictRoot",
1907
0
      "allowDroppedNullPlaceholders",
1908
0
      "allowNumericKeys",
1909
0
      "allowSingleQuotes",
1910
0
      "stackLimit",
1911
0
      "failIfExtra",
1912
0
      "rejectDupKeys",
1913
0
      "allowSpecialFloats",
1914
0
      "skipBom",
1915
0
  };
1916
0
  for (auto si = settings_.begin(); si != settings_.end(); ++si) {
1917
0
    auto key = si.name();
1918
0
    if (valid_keys.count(key))
1919
0
      continue;
1920
0
    if (invalid)
1921
0
      (*invalid)[std::move(key)] = *si;
1922
0
    else
1923
0
      return false;
1924
0
  }
1925
0
  return invalid ? invalid->empty() : true;
1926
0
}
1927
1928
0
Value& CharReaderBuilder::operator[](const String& key) {
1929
0
  return settings_[key];
1930
0
}
1931
// static
1932
0
void CharReaderBuilder::strictMode(Json::Value* settings) {
1933
  //! [CharReaderBuilderStrictMode]
1934
0
  (*settings)["allowComments"] = false;
1935
0
  (*settings)["allowTrailingCommas"] = false;
1936
0
  (*settings)["strictRoot"] = true;
1937
0
  (*settings)["allowDroppedNullPlaceholders"] = false;
1938
0
  (*settings)["allowNumericKeys"] = false;
1939
0
  (*settings)["allowSingleQuotes"] = false;
1940
0
  (*settings)["stackLimit"] = 1000;
1941
0
  (*settings)["failIfExtra"] = true;
1942
0
  (*settings)["rejectDupKeys"] = true;
1943
0
  (*settings)["allowSpecialFloats"] = false;
1944
0
  (*settings)["skipBom"] = true;
1945
  //! [CharReaderBuilderStrictMode]
1946
0
}
1947
// static
1948
25.6k
void CharReaderBuilder::setDefaults(Json::Value* settings) {
1949
  //! [CharReaderBuilderDefaults]
1950
25.6k
  (*settings)["collectComments"] = true;
1951
25.6k
  (*settings)["allowComments"] = true;
1952
25.6k
  (*settings)["allowTrailingCommas"] = true;
1953
25.6k
  (*settings)["strictRoot"] = false;
1954
25.6k
  (*settings)["allowDroppedNullPlaceholders"] = false;
1955
25.6k
  (*settings)["allowNumericKeys"] = false;
1956
25.6k
  (*settings)["allowSingleQuotes"] = false;
1957
25.6k
  (*settings)["stackLimit"] = 1000;
1958
25.6k
  (*settings)["failIfExtra"] = false;
1959
25.6k
  (*settings)["rejectDupKeys"] = false;
1960
25.6k
  (*settings)["allowSpecialFloats"] = false;
1961
25.6k
  (*settings)["skipBom"] = true;
1962
  //! [CharReaderBuilderDefaults]
1963
25.6k
}
1964
1965
//////////////////////////////////
1966
// global functions
1967
1968
bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
1969
0
                     String* errs) {
1970
0
  OStringStream ssin;
1971
0
  ssin << sin.rdbuf();
1972
0
  String doc = ssin.str();
1973
0
  char const* begin = doc.data();
1974
0
  char const* end = begin + doc.size();
1975
  // Note that we do not actually need a null-terminator.
1976
0
  CharReaderPtr const reader(fact.newCharReader());
1977
0
  return reader->parse(begin, end, root, errs);
1978
0
}
1979
1980
0
IStream& operator>>(IStream& sin, Value& root) {
1981
0
  CharReaderBuilder b;
1982
0
  String errs;
1983
0
  bool ok = parseFromStream(b, sin, &root, &errs);
1984
0
  if (!ok) {
1985
0
    throwRuntimeError(errs);
1986
0
  }
1987
0
  return sin;
1988
0
}
1989
1990
} // namespace Json