Coverage Report

Created: 2023-11-19 07:12

/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
21.3k
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
1.86k
                                OurReader::Location end) {
999
4.05k
  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
1000
1.86k
}
1001
1002
21.3k
OurReader::OurReader(OurFeatures const& features) : features_(features) {}
1003
1004
bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
1005
21.3k
                      bool collectComments) {
1006
21.3k
  if (!features_.allowComments_) {
1007
0
    collectComments = false;
1008
0
  }
1009
1010
21.3k
  begin_ = beginDoc;
1011
21.3k
  end_ = endDoc;
1012
21.3k
  collectComments_ = collectComments;
1013
21.3k
  current_ = begin_;
1014
21.3k
  lastValueEnd_ = nullptr;
1015
21.3k
  lastValue_ = nullptr;
1016
21.3k
  commentsBefore_.clear();
1017
21.3k
  errors_.clear();
1018
21.3k
  while (!nodes_.empty())
1019
0
    nodes_.pop();
1020
21.3k
  nodes_.push(&root);
1021
1022
  // skip byte order mark if it exists at the beginning of the UTF-8 text.
1023
21.3k
  skipBom(features_.skipBom_);
1024
21.3k
  bool successful = readValue();
1025
21.3k
  nodes_.pop();
1026
21.3k
  Token token;
1027
21.3k
  skipCommentTokens(token);
1028
21.3k
  if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
1029
0
    addError("Extra non-whitespace after JSON value.", token);
1030
0
    return false;
1031
0
  }
1032
21.3k
  if (collectComments_ && !commentsBefore_.empty())
1033
1.20k
    root.setComment(commentsBefore_, commentAfter);
1034
21.3k
  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
21.3k
  return successful;
1048
21.3k
}
1049
1050
53.3k
bool OurReader::readValue() {
1051
  //  To preserve the old behaviour we cast size_t to int.
1052
53.3k
  if (nodes_.size() > features_.stackLimit_)
1053
0
    throwRuntimeError("Exceeded stackLimit in readValue().");
1054
53.3k
  Token token;
1055
53.3k
  skipCommentTokens(token);
1056
53.3k
  bool successful = true;
1057
1058
53.3k
  if (collectComments_ && !commentsBefore_.empty()) {
1059
203
    currentValue().setComment(commentsBefore_, commentBefore);
1060
203
    commentsBefore_.clear();
1061
203
  }
1062
1063
53.3k
  switch (token.type_) {
1064
4.38k
  case tokenObjectBegin:
1065
4.38k
    successful = readObject(token);
1066
4.38k
    currentValue().setOffsetLimit(current_ - begin_);
1067
4.38k
    break;
1068
19.6k
  case tokenArrayBegin:
1069
19.6k
    successful = readArray(token);
1070
19.6k
    currentValue().setOffsetLimit(current_ - begin_);
1071
19.6k
    break;
1072
23.2k
  case tokenNumber:
1073
23.2k
    successful = decodeNumber(token);
1074
23.2k
    break;
1075
1.51k
  case tokenString:
1076
1.51k
    successful = decodeString(token);
1077
1.51k
    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
493
  case tokenArraySeparator:
1115
1.05k
  case tokenObjectEnd:
1116
1.05k
  case tokenArrayEnd:
1117
1.05k
    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
4.53k
  default:
1128
4.53k
    currentValue().setOffsetStart(token.start_ - begin_);
1129
4.53k
    currentValue().setOffsetLimit(token.end_ - begin_);
1130
4.53k
    return addError("Syntax error: value, object or array expected.", token);
1131
53.3k
  }
1132
1133
48.8k
  if (collectComments_) {
1134
48.8k
    lastValueEnd_ = current_;
1135
48.8k
    lastValueHasAComment_ = false;
1136
48.8k
    lastValue_ = &currentValue();
1137
48.8k
  }
1138
1139
48.8k
  return successful;
1140
53.3k
}
1141
1142
74.7k
void OurReader::skipCommentTokens(Token& token) {
1143
74.7k
  if (features_.allowComments_) {
1144
77.3k
    do {
1145
77.3k
      readToken(token);
1146
77.3k
    } while (token.type_ == tokenComment);
1147
74.7k
  } else {
1148
0
    readToken(token);
1149
0
  }
1150
74.7k
}
1151
1152
199k
bool OurReader::readToken(Token& token) {
1153
199k
  skipSpaces();
1154
199k
  token.start_ = current_;
1155
199k
  Char c = getNextChar();
1156
199k
  bool ok = true;
1157
199k
  switch (c) {
1158
4.47k
  case '{':
1159
4.47k
    token.type_ = tokenObjectBegin;
1160
4.47k
    break;
1161
3.09k
  case '}':
1162
3.09k
    token.type_ = tokenObjectEnd;
1163
3.09k
    break;
1164
21.6k
  case '[':
1165
21.6k
    token.type_ = tokenArrayBegin;
1166
21.6k
    break;
1167
8.60k
  case ']':
1168
8.60k
    token.type_ = tokenArrayEnd;
1169
8.60k
    break;
1170
7.94k
  case '"':
1171
7.94k
    token.type_ = tokenString;
1172
7.94k
    ok = readString();
1173
7.94k
    break;
1174
56
  case '\'':
1175
56
    if (features_.allowSingleQuotes_) {
1176
0
      token.type_ = tokenString;
1177
0
      ok = readStringSingleQuote();
1178
0
      break;
1179
0
    } // else fall through
1180
3.38k
  case '/':
1181
3.38k
    token.type_ = tokenComment;
1182
3.38k
    ok = readComment();
1183
3.38k
    break;
1184
532
  case '0':
1185
6.81k
  case '1':
1186
9.62k
  case '2':
1187
11.3k
  case '3':
1188
12.1k
  case '4':
1189
14.7k
  case '5':
1190
16.2k
  case '6':
1191
16.2k
  case '7':
1192
19.8k
  case '8':
1193
27.2k
  case '9':
1194
27.2k
    token.type_ = tokenNumber;
1195
27.2k
    readNumber(false);
1196
27.2k
    break;
1197
6.42k
  case '-':
1198
6.42k
    if (readNumber(true)) {
1199
5.61k
      token.type_ = tokenNumber;
1200
5.61k
    } else {
1201
804
      token.type_ = tokenNegInf;
1202
804
      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1203
804
    }
1204
6.42k
    break;
1205
21.2k
  case '+':
1206
21.2k
    if (readNumber(true)) {
1207
19.0k
      token.type_ = tokenNumber;
1208
19.0k
    } else {
1209
2.25k
      token.type_ = tokenPosInf;
1210
2.25k
      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
1211
2.25k
    }
1212
21.2k
    break;
1213
342
  case 't':
1214
342
    token.type_ = tokenTrue;
1215
342
    ok = match("rue", 3);
1216
342
    break;
1217
1.74k
  case 'f':
1218
1.74k
    token.type_ = tokenFalse;
1219
1.74k
    ok = match("alse", 4);
1220
1.74k
    break;
1221
163
  case 'n':
1222
163
    token.type_ = tokenNull;
1223
163
    ok = match("ull", 3);
1224
163
    break;
1225
23
  case 'N':
1226
23
    if (features_.allowSpecialFloats_) {
1227
0
      token.type_ = tokenNaN;
1228
0
      ok = match("aN", 2);
1229
23
    } else {
1230
23
      ok = false;
1231
23
    }
1232
23
    break;
1233
13.2k
  case 'I':
1234
13.2k
    if (features_.allowSpecialFloats_) {
1235
0
      token.type_ = tokenPosInf;
1236
0
      ok = match("nfinity", 7);
1237
13.2k
    } else {
1238
13.2k
      ok = false;
1239
13.2k
    }
1240
13.2k
    break;
1241
11.9k
  case ',':
1242
11.9k
    token.type_ = tokenArraySeparator;
1243
11.9k
    break;
1244
3.30k
  case ':':
1245
3.30k
    token.type_ = tokenMemberSeparator;
1246
3.30k
    break;
1247
33.5k
  case 0:
1248
33.5k
    token.type_ = tokenEndOfStream;
1249
33.5k
    break;
1250
30.7k
  default:
1251
30.7k
    ok = false;
1252
30.7k
    break;
1253
199k
  }
1254
199k
  if (!ok)
1255
52.5k
    token.type_ = tokenError;
1256
199k
  token.end_ = current_;
1257
199k
  return ok;
1258
199k
}
1259
1260
228k
void OurReader::skipSpaces() {
1261
229k
  while (current_ != end_) {
1262
198k
    Char c = *current_;
1263
198k
    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1264
761
      ++current_;
1265
197k
    else
1266
197k
      break;
1267
198k
  }
1268
228k
}
1269
1270
21.3k
void OurReader::skipBom(bool skipBom) {
1271
  // The default behavior is to skip BOM.
1272
21.3k
  if (skipBom) {
1273
21.3k
    if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
1274
46
      begin_ += 3;
1275
46
      current_ = begin_;
1276
46
    }
1277
21.3k
  }
1278
21.3k
}
1279
1280
2.25k
bool OurReader::match(const Char* pattern, int patternLength) {
1281
2.25k
  if (end_ - current_ < patternLength)
1282
197
    return false;
1283
2.05k
  int index = patternLength;
1284
2.23k
  while (index--)
1285
2.23k
    if (current_[index] != pattern[index])
1286
2.05k
      return false;
1287
0
  current_ += patternLength;
1288
0
  return true;
1289
2.05k
}
1290
1291
3.38k
bool OurReader::readComment() {
1292
3.38k
  const Location commentBegin = current_ - 1;
1293
3.38k
  const Char c = getNextChar();
1294
3.38k
  bool successful = false;
1295
3.38k
  bool cStyleWithEmbeddedNewline = false;
1296
1297
3.38k
  const bool isCStyleComment = (c == '*');
1298
3.38k
  const bool isCppStyleComment = (c == '/');
1299
3.38k
  if (isCStyleComment) {
1300
1.89k
    successful = readCStyleComment(&cStyleWithEmbeddedNewline);
1301
1.89k
  } else if (isCppStyleComment) {
1302
1.24k
    successful = readCppStyleComment();
1303
1.24k
  }
1304
1305
3.38k
  if (!successful)
1306
764
    return false;
1307
1308
2.61k
  if (collectComments_) {
1309
2.61k
    CommentPlacement placement = commentBefore;
1310
1311
2.61k
    if (!lastValueHasAComment_) {
1312
2.12k
      if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
1313
1.19k
        if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
1314
517
          placement = commentAfterOnSameLine;
1315
517
          lastValueHasAComment_ = true;
1316
517
        }
1317
1.19k
      }
1318
2.12k
    }
1319
1320
2.61k
    addComment(commentBegin, current_, placement);
1321
2.61k
  }
1322
2.61k
  return true;
1323
3.38k
}
1324
1325
String OurReader::normalizeEOL(OurReader::Location begin,
1326
2.61k
                               OurReader::Location end) {
1327
2.61k
  String normalized;
1328
2.61k
  normalized.reserve(static_cast<size_t>(end - begin));
1329
2.61k
  OurReader::Location current = begin;
1330
20.9k
  while (current != end) {
1331
18.3k
    char c = *current++;
1332
18.3k
    if (c == '\r') {
1333
239
      if (current != end && *current == '\n')
1334
        // convert dos EOL
1335
167
        ++current;
1336
      // convert Mac EOL
1337
239
      normalized += '\n';
1338
18.0k
    } else {
1339
18.0k
      normalized += c;
1340
18.0k
    }
1341
18.3k
  }
1342
2.61k
  return normalized;
1343
2.61k
}
1344
1345
void OurReader::addComment(Location begin, Location end,
1346
2.61k
                           CommentPlacement placement) {
1347
2.61k
  assert(collectComments_);
1348
2.61k
  const String& normalized = normalizeEOL(begin, end);
1349
2.61k
  if (placement == commentAfterOnSameLine) {
1350
517
    assert(lastValue_ != nullptr);
1351
517
    lastValue_->setComment(normalized, placement);
1352
2.10k
  } else {
1353
2.10k
    commentsBefore_ += normalized;
1354
2.10k
  }
1355
2.61k
}
1356
1357
1.89k
bool OurReader::readCStyleComment(bool* containsNewLineResult) {
1358
1.89k
  *containsNewLineResult = false;
1359
1360
15.9k
  while ((current_ + 1) < end_) {
1361
15.4k
    Char c = getNextChar();
1362
15.4k
    if (c == '*' && *current_ == '/')
1363
1.37k
      break;
1364
14.0k
    if (c == '\n')
1365
1.31k
      *containsNewLineResult = true;
1366
14.0k
  }
1367
1368
1.89k
  return getNextChar() == '/';
1369
1.89k
}
1370
1371
1.24k
bool OurReader::readCppStyleComment() {
1372
3.43k
  while (current_ != end_) {
1373
2.60k
    Char c = getNextChar();
1374
2.60k
    if (c == '\n')
1375
365
      break;
1376
2.23k
    if (c == '\r') {
1377
      // Consume DOS EOL. It will be normalized in addComment.
1378
40
      if (current_ != end_ && *current_ == '\n')
1379
0
        getNextChar();
1380
      // Break on Moc OS 9 EOL.
1381
40
      break;
1382
40
    }
1383
2.23k
  }
1384
1.24k
  return true;
1385
1.24k
}
1386
1387
54.9k
bool OurReader::readNumber(bool checkInf) {
1388
54.9k
  Location p = current_;
1389
54.9k
  if (checkInf && p != end_ && *p == 'I') {
1390
3.05k
    current_ = ++p;
1391
3.05k
    return false;
1392
3.05k
  }
1393
51.9k
  char c = '0'; // stopgap for already consumed character
1394
  // integral part
1395
156k
  while (c >= '0' && c <= '9')
1396
104k
    c = (current_ = p) < end_ ? *p++ : '\0';
1397
  // fractional part
1398
51.9k
  if (c == '.') {
1399
1.04k
    c = (current_ = p) < end_ ? *p++ : '\0';
1400
2.08k
    while (c >= '0' && c <= '9')
1401
1.04k
      c = (current_ = p) < end_ ? *p++ : '\0';
1402
1.04k
  }
1403
  // exponential part
1404
51.9k
  if (c == 'e' || c == 'E') {
1405
3.81k
    c = (current_ = p) < end_ ? *p++ : '\0';
1406
3.81k
    if (c == '+' || c == '-')
1407
1.51k
      c = (current_ = p) < end_ ? *p++ : '\0';
1408
8.68k
    while (c >= '0' && c <= '9')
1409
4.86k
      c = (current_ = p) < end_ ? *p++ : '\0';
1410
3.81k
  }
1411
51.9k
  return true;
1412
54.9k
}
1413
7.94k
bool OurReader::readString() {
1414
7.94k
  Char c = 0;
1415
39.4k
  while (current_ != end_) {
1416
36.9k
    c = getNextChar();
1417
36.9k
    if (c == '\\')
1418
5.07k
      getNextChar();
1419
31.8k
    else if (c == '"')
1420
5.47k
      break;
1421
36.9k
  }
1422
7.94k
  return c == '"';
1423
7.94k
}
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
4.38k
bool OurReader::readObject(Token& token) {
1438
4.38k
  Token tokenName;
1439
4.38k
  String name;
1440
4.38k
  Value init(objectValue);
1441
4.38k
  currentValue().swapPayload(init);
1442
4.38k
  currentValue().setOffsetStart(token.start_ - begin_);
1443
4.82k
  while (readToken(tokenName)) {
1444
4.47k
    bool initialTokenOk = true;
1445
4.50k
    while (tokenName.type_ == tokenComment && initialTokenOk)
1446
27
      initialTokenOk = readToken(tokenName);
1447
4.47k
    if (!initialTokenOk)
1448
1
      break;
1449
4.47k
    if (tokenName.type_ == tokenObjectEnd &&
1450
4.47k
        (name.empty() ||
1451
130
         features_.allowTrailingCommas_)) // empty object or trailing comma
1452
130
      return true;
1453
4.34k
    name.clear();
1454
4.34k
    if (tokenName.type_ == tokenString) {
1455
3.78k
      if (!decodeString(tokenName, name))
1456
410
        return recoverFromError(tokenObjectEnd);
1457
3.78k
    } 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
561
    } else {
1463
561
      break;
1464
561
    }
1465
3.37k
    if (name.length() >= (1U << 30))
1466
0
      throwRuntimeError("keylength >= 2^30");
1467
3.37k
    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1468
0
      String msg = "Duplicate key: '" + name + "'";
1469
0
      return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
1470
0
    }
1471
1472
3.37k
    Token colon;
1473
3.37k
    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
1474
1.04k
      return addErrorAndRecover("Missing ':' after object member name", colon,
1475
1.04k
                                tokenObjectEnd);
1476
1.04k
    }
1477
2.33k
    Value& value = currentValue()[name];
1478
2.33k
    nodes_.push(&value);
1479
2.33k
    bool ok = readValue();
1480
2.33k
    nodes_.pop();
1481
2.33k
    if (!ok) // error already set
1482
1.37k
      return recoverFromError(tokenObjectEnd);
1483
1484
953
    Token comma;
1485
953
    if (!readToken(comma) ||
1486
953
        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
1487
796
         comma.type_ != tokenComment)) {
1488
168
      return addErrorAndRecover("Missing ',' or '}' in object declaration",
1489
168
                                comma, tokenObjectEnd);
1490
168
    }
1491
785
    bool finalizeTokenOk = true;
1492
785
    while (comma.type_ == tokenComment && finalizeTokenOk)
1493
0
      finalizeTokenOk = readToken(comma);
1494
785
    if (comma.type_ == tokenObjectEnd)
1495
350
      return true;
1496
785
  }
1497
907
  return addErrorAndRecover("Missing '}' or object member name", tokenName,
1498
907
                            tokenObjectEnd);
1499
4.38k
}
1500
1501
19.6k
bool OurReader::readArray(Token& token) {
1502
19.6k
  Value init(arrayValue);
1503
19.6k
  currentValue().swapPayload(init);
1504
19.6k
  currentValue().setOffsetStart(token.start_ - begin_);
1505
19.6k
  int index = 0;
1506
29.8k
  for (;;) {
1507
29.8k
    skipSpaces();
1508
29.8k
    if (current_ != end_ && *current_ == ']' &&
1509
29.8k
        (index == 0 ||
1510
127
         (features_.allowTrailingCommas_ &&
1511
106
          !features_.allowDroppedNullPlaceholders_))) // empty array or trailing
1512
                                                      // comma
1513
127
    {
1514
127
      Token endArray;
1515
127
      readToken(endArray);
1516
127
      return true;
1517
127
    }
1518
29.7k
    Value& value = currentValue()[index++];
1519
29.7k
    nodes_.push(&value);
1520
29.7k
    bool ok = readValue();
1521
29.7k
    nodes_.pop();
1522
29.7k
    if (!ok) // error already set
1523
6.33k
      return recoverFromError(tokenArrayEnd);
1524
1525
23.3k
    Token currentToken;
1526
    // Accept Comment after last item in the array.
1527
23.3k
    ok = readToken(currentToken);
1528
23.3k
    while (currentToken.type_ == tokenComment && ok) {
1529
1
      ok = readToken(currentToken);
1530
1
    }
1531
23.3k
    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
1532
23.3k
                         currentToken.type_ != tokenArrayEnd);
1533
23.3k
    if (!ok || badTokenType) {
1534
6.73k
      return addErrorAndRecover("Missing ',' or ']' in array declaration",
1535
6.73k
                                currentToken, tokenArrayEnd);
1536
6.73k
    }
1537
16.6k
    if (currentToken.type_ == tokenArrayEnd)
1538
6.49k
      break;
1539
16.6k
  }
1540
6.49k
  return true;
1541
19.6k
}
1542
1543
23.2k
bool OurReader::decodeNumber(Token& token) {
1544
23.2k
  Value decoded;
1545
23.2k
  if (!decodeNumber(token, decoded))
1546
1.19k
    return false;
1547
22.0k
  currentValue().swapPayload(decoded);
1548
22.0k
  currentValue().setOffsetStart(token.start_ - begin_);
1549
22.0k
  currentValue().setOffsetLimit(token.end_ - begin_);
1550
22.0k
  return true;
1551
23.2k
}
1552
1553
23.2k
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
23.2k
  Location current = token.start_;
1558
23.2k
  const bool isNegative = *current == '-';
1559
23.2k
  if (isNegative) {
1560
1.48k
    ++current;
1561
1.48k
  }
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
23.2k
  static_assert(Value::maxLargestInt <= Value::maxLargestUInt,
1567
23.2k
                "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
23.2k
  static_assert(Value::minLargestInt <= -Value::maxLargestInt,
1574
23.2k
                "The absolute value of minLargestInt must be greater than or "
1575
23.2k
                "equal to maxLargestInt");
1576
23.2k
  static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,
1577
23.2k
                "The absolute value of minLargestInt must be only 1 magnitude "
1578
23.2k
                "larger than maxLargest Int");
1579
1580
23.2k
  static constexpr Value::LargestUInt positive_threshold =
1581
23.2k
      Value::maxLargestUInt / 10;
1582
23.2k
  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
23.2k
  static constexpr auto negative_threshold =
1590
23.2k
      Value::LargestUInt(-(Value::minLargestInt / 10));
1591
23.2k
  static constexpr auto negative_last_digit =
1592
23.2k
      Value::UInt(-(Value::minLargestInt % 10));
1593
1594
23.2k
  const Value::LargestUInt threshold =
1595
23.2k
      isNegative ? negative_threshold : positive_threshold;
1596
23.2k
  const Value::UInt max_last_digit =
1597
23.2k
      isNegative ? negative_last_digit : positive_last_digit;
1598
1599
23.2k
  Value::LargestUInt value = 0;
1600
84.7k
  while (current < token.end_) {
1601
64.9k
    Char c = *current++;
1602
64.9k
    if (c < '0' || c > '9')
1603
3.49k
      return decodeDouble(token, decoded);
1604
1605
61.4k
    const auto digit(static_cast<Value::UInt>(c - '0'));
1606
61.4k
    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
61.4k
    value = value * 10 + digit;
1618
61.4k
  }
1619
1620
19.7k
  if (isNegative) {
1621
    // We use the same magnitude assumption here, just in case.
1622
204
    const auto last_digit = static_cast<Value::UInt>(value % 10);
1623
204
    decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
1624
19.5k
  } else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
1625
19.5k
    decoded = Value::LargestInt(value);
1626
19.5k
  } else {
1627
0
    decoded = value;
1628
0
  }
1629
1630
19.7k
  return true;
1631
23.2k
}
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
3.49k
bool OurReader::decodeDouble(Token& token, Value& decoded) {
1644
3.49k
  double value = 0;
1645
3.49k
  const String buffer(token.start_, token.end_);
1646
3.49k
  IStringStream is(buffer);
1647
3.49k
  if (!(is >> value)) {
1648
1.19k
    return addError(
1649
1.19k
        "'" + String(token.start_, token.end_) + "' is not a number.", token);
1650
1.19k
  }
1651
2.29k
  decoded = value;
1652
2.29k
  return true;
1653
3.49k
}
1654
1655
1.51k
bool OurReader::decodeString(Token& token) {
1656
1.51k
  String decoded_string;
1657
1.51k
  if (!decodeString(token, decoded_string))
1658
710
    return false;
1659
808
  Value decoded(decoded_string);
1660
808
  currentValue().swapPayload(decoded);
1661
808
  currentValue().setOffsetStart(token.start_ - begin_);
1662
808
  currentValue().setOffsetLimit(token.end_ - begin_);
1663
808
  return true;
1664
1.51k
}
1665
1666
5.30k
bool OurReader::decodeString(Token& token, String& decoded) {
1667
5.30k
  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
1668
5.30k
  Location current = token.start_ + 1; // skip '"'
1669
5.30k
  Location end = token.end_ - 1;       // do not include '"'
1670
12.6k
  while (current != end) {
1671
8.50k
    Char c = *current++;
1672
8.50k
    if (c == '"')
1673
0
      break;
1674
8.50k
    if (c == '\\') {
1675
2.25k
      if (current == end)
1676
0
        return addError("Empty escape sequence in string", token, current);
1677
2.25k
      Char escape = *current++;
1678
2.25k
      switch (escape) {
1679
3
      case '"':
1680
3
        decoded += '"';
1681
3
        break;
1682
4
      case '/':
1683
4
        decoded += '/';
1684
4
        break;
1685
826
      case '\\':
1686
826
        decoded += '\\';
1687
826
        break;
1688
2
      case 'b':
1689
2
        decoded += '\b';
1690
2
        break;
1691
0
      case 'f':
1692
0
        decoded += '\f';
1693
0
        break;
1694
5
      case 'n':
1695
5
        decoded += '\n';
1696
5
        break;
1697
2
      case 'r':
1698
2
        decoded += '\r';
1699
2
        break;
1700
4
      case 't':
1701
4
        decoded += '\t';
1702
4
        break;
1703
968
      case 'u': {
1704
968
        unsigned int unicode;
1705
968
        if (!decodeUnicodeCodePoint(token, current, end, unicode))
1706
678
          return false;
1707
290
        decoded += codePointToUTF8(unicode);
1708
290
      } break;
1709
442
      default:
1710
442
        return addError("Bad escape sequence in string", token, current);
1711
2.25k
      }
1712
6.24k
    } else {
1713
6.24k
      decoded += c;
1714
6.24k
    }
1715
8.50k
  }
1716
4.18k
  return true;
1717
5.30k
}
1718
1719
bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
1720
968
                                       Location end, unsigned int& unicode) {
1721
1722
968
  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
1723
678
    return false;
1724
290
  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
290
  return true;
1742
290
}
1743
1744
bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
1745
                                            Location end,
1746
968
                                            unsigned int& ret_unicode) {
1747
968
  if (end - current < 4)
1748
1
    return addError(
1749
1
        "Bad unicode escape sequence in string: four digits expected.", token,
1750
1
        current);
1751
967
  int unicode = 0;
1752
3.12k
  for (int index = 0; index < 4; ++index) {
1753
2.83k
    Char c = *current++;
1754
2.83k
    unicode *= 16;
1755
2.83k
    if (c >= '0' && c <= '9')
1756
51
      unicode += c - '0';
1757
2.78k
    else if (c >= 'a' && c <= 'f')
1758
615
      unicode += c - 'a' + 10;
1759
2.16k
    else if (c >= 'A' && c <= 'F')
1760
1.48k
      unicode += c - 'A' + 10;
1761
677
    else
1762
677
      return addError(
1763
677
          "Bad unicode escape sequence in string: hexadecimal digit expected.",
1764
677
          token, current);
1765
2.83k
  }
1766
290
  ret_unicode = static_cast<unsigned int>(unicode);
1767
290
  return true;
1768
967
}
1769
1770
15.7k
bool OurReader::addError(const String& message, Token& token, Location extra) {
1771
15.7k
  ErrorInfo info;
1772
15.7k
  info.token_ = token;
1773
15.7k
  info.message_ = message;
1774
15.7k
  info.extra_ = extra;
1775
15.7k
  errors_.push_back(info);
1776
15.7k
  return false;
1777
15.7k
}
1778
1779
16.9k
bool OurReader::recoverFromError(TokenType skipUntilToken) {
1780
16.9k
  size_t errorCount = errors_.size();
1781
16.9k
  Token skip;
1782
89.1k
  for (;;) {
1783
89.1k
    if (!readToken(skip))
1784
45.3k
      errors_.resize(errorCount); // discard errors caused by recovery
1785
89.1k
    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
1786
16.9k
      break;
1787
89.1k
  }
1788
16.9k
  errors_.resize(errorCount);
1789
16.9k
  return false;
1790
16.9k
}
1791
1792
bool OurReader::addErrorAndRecover(const String& message, Token& token,
1793
8.85k
                                   TokenType skipUntilToken) {
1794
8.85k
  addError(message, token);
1795
8.85k
  return recoverFromError(skipUntilToken);
1796
8.85k
}
1797
1798
231k
Value& OurReader::currentValue() { return *(nodes_.top()); }
1799
1800
264k
OurReader::Char OurReader::getNextChar() {
1801
264k
  if (current_ == end_)
1802
31.3k
    return 0;
1803
233k
  return *current_++;
1804
264k
}
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
21.3k
      : collectComments_(collectComments), reader_(features) {}
1868
  bool parse(char const* beginDoc, char const* endDoc, Value* root,
1869
21.3k
             String* errs) override {
1870
21.3k
    bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
1871
21.3k
    if (errs) {
1872
0
      *errs = reader_.getFormattedErrorMessages();
1873
0
    }
1874
21.3k
    return ok;
1875
21.3k
  }
1876
};
1877
1878
21.3k
CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
1879
21.3k
CharReaderBuilder::~CharReaderBuilder() = default;
1880
21.3k
CharReader* CharReaderBuilder::newCharReader() const {
1881
21.3k
  bool collectComments = settings_["collectComments"].asBool();
1882
21.3k
  OurFeatures features = OurFeatures::all();
1883
21.3k
  features.allowComments_ = settings_["allowComments"].asBool();
1884
21.3k
  features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
1885
21.3k
  features.strictRoot_ = settings_["strictRoot"].asBool();
1886
21.3k
  features.allowDroppedNullPlaceholders_ =
1887
21.3k
      settings_["allowDroppedNullPlaceholders"].asBool();
1888
21.3k
  features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
1889
21.3k
  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
21.3k
  features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());
1894
21.3k
  features.failIfExtra_ = settings_["failIfExtra"].asBool();
1895
21.3k
  features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
1896
21.3k
  features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
1897
21.3k
  features.skipBom_ = settings_["skipBom"].asBool();
1898
21.3k
  return new OurCharReader(collectComments, features);
1899
21.3k
}
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
21.3k
void CharReaderBuilder::setDefaults(Json::Value* settings) {
1949
  //! [CharReaderBuilderDefaults]
1950
21.3k
  (*settings)["collectComments"] = true;
1951
21.3k
  (*settings)["allowComments"] = true;
1952
21.3k
  (*settings)["allowTrailingCommas"] = true;
1953
21.3k
  (*settings)["strictRoot"] = false;
1954
21.3k
  (*settings)["allowDroppedNullPlaceholders"] = false;
1955
21.3k
  (*settings)["allowNumericKeys"] = false;
1956
21.3k
  (*settings)["allowSingleQuotes"] = false;
1957
21.3k
  (*settings)["stackLimit"] = 1000;
1958
21.3k
  (*settings)["failIfExtra"] = false;
1959
21.3k
  (*settings)["rejectDupKeys"] = false;
1960
21.3k
  (*settings)["allowSpecialFloats"] = false;
1961
21.3k
  (*settings)["skipBom"] = true;
1962
  //! [CharReaderBuilderDefaults]
1963
21.3k
}
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