Coverage Report

Created: 2017-11-21 16:49

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/External/JSON/json_reader.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <json/reader.h>
2
#include <json/value.h>
3
#include <utility>
4
#include <cstdio>
5
#include <cassert>
6
#include <cstring>
7
#include <iostream>
8
#include <stdexcept>
9
10
#if _MSC_VER >= 1400 // VC++ 8.0
11
#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
12
#endif
13
14
namespace Json {
15
16
// Implementation of class Features
17
// ////////////////////////////////
18
19
Features::Features()
20
   : allowComments_( true )
21
   , strictRoot_( false )
22
39
{
23
39
}
24
25
26
Features 
27
Features::all()
28
39
{
29
39
   return Features();
30
39
}
31
32
33
Features 
34
Features::strictMode()
35
0
{
36
0
   Features features;
37
0
   features.allowComments_ = false;
38
0
   features.strictRoot_ = true;
39
0
   return features;
40
0
}
41
42
// Implementation of class Reader
43
// ////////////////////////////////
44
45
46
static inline bool 
47
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
48
0
{
49
0
   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4;
50
0
}
51
52
static inline bool 
53
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
54
0
{
55
0
   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4  ||  c == c5;
56
0
}
57
58
59
static bool 
60
containsNewLine( Reader::Location begin, 
61
                 Reader::Location end )
62
0
{
63
0
   for ( ;begin < end; ++begin )
64
0
      if ( *begin == '\n'  ||  *begin == '\r' )
65
0
         return true;
66
0
   return false;
67
0
}
68
69
static std::string codePointToUTF8(unsigned int cp)
70
0
{
71
0
   std::string result;
72
0
   
73
0
   // based on description from http://en.wikipedia.org/wiki/UTF-8
74
0
75
0
   if (cp <= 0x7f) 
76
0
   {
77
0
      result.resize(1);
78
0
      result[0] = static_cast<char>(cp);
79
0
   } 
80
0
   else if (cp <= 0x7FF) 
81
0
   {
82
0
      result.resize(2);
83
0
      result[1] = static_cast<char>(0x80 | (0x3f & cp));
84
0
      result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
85
0
   } 
86
0
   else if (cp <= 0xFFFF) 
87
0
   {
88
0
      result.resize(3);
89
0
      result[2] = static_cast<char>(0x80 | (0x3f & cp));
90
0
      result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
91
0
      result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
92
0
   }
93
0
   else if (cp <= 0x10FFFF) 
94
0
   {
95
0
      result.resize(4);
96
0
      result[3] = static_cast<char>(0x80 | (0x3f & cp));
97
0
      result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
98
0
      result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
99
0
      result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
100
0
   }
101
0
102
0
   return result;
103
0
}
104
105
106
// Class Reader
107
// //////////////////////////////////////////////////////////////////
108
109
Reader::Reader()
110
   : features_( Features::all() )
111
39
{
112
39
}
113
114
115
Reader::Reader( const Features &features )
116
   : features_( features )
117
0
{
118
0
}
119
120
121
bool
122
Reader::parse( const std::string &document, 
123
               Value &root,
124
               bool collectComments )
125
39
{
126
39
   document_ = document;
127
39
   const char *begin = document_.c_str();
128
39
   const char *end = begin + document_.length();
129
39
   return parse( begin, end, root, collectComments );
130
39
}
131
132
133
bool
134
Reader::parse( std::istream& sin,
135
               Value &root,
136
               bool collectComments )
137
0
{
138
0
   //std::istream_iterator<char> begin(sin);
139
0
   //std::istream_iterator<char> end;
140
0
   // Those would allow streamed input from a file, if parse() were a
141
0
   // template function.
142
0
143
0
   // Since std::string is reference-counted, this at least does not
144
0
   // create an extra copy.
145
0
   std::string doc;
146
0
   std::getline(sin, doc, (char)EOF);
147
0
   return parse( doc, root, collectComments );
148
0
}
149
150
bool 
151
Reader::parse( const char *beginDoc, const char *endDoc, 
152
               Value &root,
153
               bool collectComments )
154
39
{
155
39
   if ( !features_.allowComments_ )
156
0
   {
157
0
      collectComments = false;
158
0
   }
159
39
160
39
   begin_ = beginDoc;
161
39
   end_ = endDoc;
162
39
   collectComments_ = collectComments;
163
39
   current_ = begin_;
164
39
   lastValueEnd_ = 0;
165
39
   lastValue_ = 0;
166
39
   commentsBefore_ = "";
167
39
   errors_.clear();
168
39
   while ( !nodes_.empty() )
169
39
      
nodes_.pop()0
;
170
39
   nodes_.push( &root );
171
39
   
172
39
   bool successful = readValue();
173
39
   Token token;
174
39
   skipCommentTokens( token );
175
39
   if ( collectComments_  &&  !commentsBefore_.empty() )
176
0
      root.setComment( commentsBefore_, commentAfter );
177
39
   if ( features_.strictRoot_ )
178
0
   {
179
0
      if ( !root.isArray()  &&  !root.isObject() )
180
0
      {
181
0
         // Set error location to start of doc, ideally should be first token found in doc
182
0
         token.type_ = tokenError;
183
0
         token.start_ = beginDoc;
184
0
         token.end_ = endDoc;
185
0
         addError( "A valid JSON document must be either an array or an object value.",
186
0
                   token );
187
0
         return false;
188
0
      }
189
39
   }
190
39
   return successful;
191
39
}
192
193
194
bool
195
Reader::readValue()
196
1.13k
{
197
1.13k
   Token token;
198
1.13k
   skipCommentTokens( token );
199
1.13k
   bool successful = true;
200
1.13k
201
1.13k
   if ( collectComments_  &&  !commentsBefore_.empty() )
202
0
   {
203
0
      currentValue().setComment( commentsBefore_, commentBefore );
204
0
      commentsBefore_ = "";
205
0
   }
206
1.13k
207
1.13k
208
1.13k
   switch ( token.type_ )
209
1.13k
   {
210
1.13k
   case tokenObjectBegin:
211
281
      successful = readObject( token );
212
281
      break;
213
1.13k
   case tokenArrayBegin:
214
171
      successful = readArray( token );
215
171
      break;
216
1.13k
   case tokenNumber:
217
0
      successful = decodeNumber( token );
218
0
      break;
219
1.13k
   case tokenString:
220
684
      successful = decodeString( token );
221
684
      break;
222
1.13k
   case tokenTrue:
223
0
      currentValue() = true;
224
0
      break;
225
1.13k
   case tokenFalse:
226
0
      currentValue() = false;
227
0
      break;
228
1.13k
   case tokenNull:
229
0
      currentValue() = Value();
230
0
      break;
231
1.13k
   default:
232
0
      return addError( "Syntax error: value, object or array expected.", token );
233
1.13k
   }
234
1.13k
235
1.13k
   if ( collectComments_ )
236
1.13k
   {
237
1.13k
      lastValueEnd_ = current_;
238
1.13k
      lastValue_ = &currentValue();
239
1.13k
   }
240
1.13k
241
1.13k
   return successful;
242
1.13k
}
243
244
245
void 
246
Reader::skipCommentTokens( Token &token )
247
1.17k
{
248
1.17k
   if ( features_.allowComments_ )
249
1.17k
   {
250
1.17k
      do
251
1.17k
      {
252
1.17k
         readToken( token );
253
1.17k
      }
254
1.17k
      while ( token.type_ == tokenComment );
255
1.17k
   }
256
0
   else
257
0
   {
258
0
      readToken( token );
259
0
   }
260
1.17k
}
261
262
263
bool 
264
Reader::expectToken( TokenType type, Token &token, const char *message )
265
0
{
266
0
   readToken( token );
267
0
   if ( token.type_ != type )
268
0
      return addError( message, token );
269
0
   return true;
270
0
}
271
272
273
bool 
274
Reader::readToken( Token &token )
275
3.86k
{
276
3.86k
   skipSpaces();
277
3.86k
   token.start_ = current_;
278
3.86k
   Char c = getNextChar();
279
3.86k
   bool ok = true;
280
3.86k
   switch ( c )
281
3.86k
   {
282
3.86k
   case '{':
283
281
      token.type_ = tokenObjectBegin;
284
281
      break;
285
3.86k
   case '}':
286
281
      token.type_ = tokenObjectEnd;
287
281
      break;
288
3.86k
   case '[':
289
171
      token.type_ = tokenArrayBegin;
290
171
      break;
291
3.86k
   case ']':
292
171
      token.type_ = tokenArrayEnd;
293
171
      break;
294
3.86k
   case '"':
295
1.47k
      token.type_ = tokenString;
296
1.47k
      ok = readString();
297
1.47k
      break;
298
3.86k
   case '/':
299
0
      token.type_ = tokenComment;
300
0
      ok = readComment();
301
0
      break;
302
3.86k
   case '0':
303
0
   case '1':
304
0
   case '2':
305
0
   case '3':
306
0
   case '4':
307
0
   case '5':
308
0
   case '6':
309
0
   case '7':
310
0
   case '8':
311
0
   case '9':
312
0
   case '-':
313
0
      token.type_ = tokenNumber;
314
0
      readNumber();
315
0
      break;
316
0
   case 't':
317
0
      token.type_ = tokenTrue;
318
0
      ok = match( "rue", 3 );
319
0
      break;
320
0
   case 'f':
321
0
      token.type_ = tokenFalse;
322
0
      ok = match( "alse", 4 );
323
0
      break;
324
0
   case 'n':
325
0
      token.type_ = tokenNull;
326
0
      ok = match( "ull", 3 );
327
0
      break;
328
645
   case ',':
329
645
      token.type_ = tokenArraySeparator;
330
645
      break;
331
794
   case ':':
332
794
      token.type_ = tokenMemberSeparator;
333
794
      break;
334
39
   case 0:
335
39
      token.type_ = tokenEndOfStream;
336
39
      break;
337
0
   default:
338
0
      ok = false;
339
0
      break;
340
3.86k
   }
341
3.86k
   if ( !ok )
342
0
      token.type_ = tokenError;
343
3.86k
   token.end_ = current_;
344
3.86k
   return true;
345
3.86k
}
346
347
348
void 
349
Reader::skipSpaces()
350
4.03k
{
351
20.2k
   while ( current_ != end_ )
352
20.2k
   {
353
20.2k
      Char c = *current_;
354
20.2k
      if ( c == ' '  ||  
c == '\t'5.47k
||
c == '\r'5.47k
||
c == '\n'5.47k
)
355
16.2k
         ++current_;
356
3.99k
      else
357
3.99k
         break;
358
20.2k
   }
359
4.03k
}
360
361
362
bool 
363
Reader::match( Location pattern, 
364
               int patternLength )
365
0
{
366
0
   if ( end_ - current_ < patternLength )
367
0
      return false;
368
0
   int index = patternLength;
369
0
   while ( index-- )
370
0
      if ( current_[index] != pattern[index] )
371
0
         return false;
372
0
   current_ += patternLength;
373
0
   return true;
374
0
}
375
376
377
bool
378
Reader::readComment()
379
0
{
380
0
   Location commentBegin = current_ - 1;
381
0
   Char c = getNextChar();
382
0
   bool successful = false;
383
0
   if ( c == '*' )
384
0
      successful = readCStyleComment();
385
0
   else if ( c == '/' )
386
0
      successful = readCppStyleComment();
387
0
   if ( !successful )
388
0
      return false;
389
0
390
0
   if ( collectComments_ )
391
0
   {
392
0
      CommentPlacement placement = commentBefore;
393
0
      if ( lastValueEnd_  &&  !containsNewLine( lastValueEnd_, commentBegin ) )
394
0
      {
395
0
         if ( c != '*'  ||  !containsNewLine( commentBegin, current_ ) )
396
0
            placement = commentAfterOnSameLine;
397
0
      }
398
0
399
0
      addComment( commentBegin, current_, placement );
400
0
   }
401
0
   return true;
402
0
}
403
404
405
void 
406
Reader::addComment( Location begin, 
407
                    Location end, 
408
                    CommentPlacement placement )
409
0
{
410
0
   assert( collectComments_ );
411
0
   if ( placement == commentAfterOnSameLine )
412
0
   {
413
0
      assert( lastValue_ != 0 );
414
0
      lastValue_->setComment( std::string( begin, end ), placement );
415
0
   }
416
0
   else
417
0
   {
418
0
      if ( !commentsBefore_.empty() )
419
0
         commentsBefore_ += "\n";
420
0
      commentsBefore_ += std::string( begin, end );
421
0
   }
422
0
}
423
424
425
bool 
426
Reader::readCStyleComment()
427
0
{
428
0
   while ( current_ != end_ )
429
0
   {
430
0
      Char c = getNextChar();
431
0
      if ( c == '*'  &&  *current_ == '/' )
432
0
         break;
433
0
   }
434
0
   return getNextChar() == '/';
435
0
}
436
437
438
bool 
439
Reader::readCppStyleComment()
440
0
{
441
0
   while ( current_ != end_ )
442
0
   {
443
0
      Char c = getNextChar();
444
0
      if (  c == '\r'  ||  c == '\n' )
445
0
         break;
446
0
   }
447
0
   return true;
448
0
}
449
450
451
void 
452
Reader::readNumber()
453
0
{
454
0
   while ( current_ != end_ )
455
0
   {
456
0
      if ( !(*current_ >= '0'  &&  *current_ <= '9')  &&
457
0
           !in( *current_, '.', 'e', 'E', '+', '-' ) )
458
0
         break;
459
0
      ++current_;
460
0
   }
461
0
}
462
463
bool
464
Reader::readString()
465
1.47k
{
466
1.47k
   Char c = 0;
467
22.5k
   while ( current_ != end_ )
468
22.5k
   {
469
22.5k
      c = getNextChar();
470
22.5k
      if ( c == '\\' )
471
0
         getNextChar();
472
22.5k
      else if ( c == '"' )
473
1.47k
         break;
474
22.5k
   }
475
1.47k
   return c == '"';
476
1.47k
}
477
478
479
bool 
480
Reader::readObject( Token &tokenStart )
481
281
{
482
281
   Token tokenName;
483
281
   std::string name;
484
281
   currentValue() = Value( objectValue );
485
794
   while ( readToken( tokenName ) )
486
794
   {
487
794
      bool initialTokenOk = true;
488
794
      while ( tokenName.type_ == tokenComment  &&  
initialTokenOk0
)
489
794
         
initialTokenOk = readToken( tokenName )0
;
490
794
      if  ( !initialTokenOk )
491
0
         break;
492
794
      if ( tokenName.type_ == tokenObjectEnd  &&  
name.empty()0
) // empty object
493
0
         return true;
494
794
      if ( tokenName.type_ != tokenString )
495
0
         break;
496
794
      
497
794
      name = "";
498
794
      if ( !decodeString( tokenName, name ) )
499
0
         return recoverFromError( tokenObjectEnd );
500
794
501
794
      Token colon;
502
794
      if ( !readToken( colon ) ||  colon.type_ != tokenMemberSeparator )
503
0
      {
504
0
         return addErrorAndRecover( "Missing ':' after object member name", 
505
0
                                    colon, 
506
0
                                    tokenObjectEnd );
507
0
      }
508
794
      Value &value = currentValue()[ name ];
509
794
      nodes_.push( &value );
510
794
      bool ok = readValue();
511
794
      nodes_.pop();
512
794
      if ( !ok ) // error already set
513
0
         return recoverFromError( tokenObjectEnd );
514
794
515
794
      Token comma;
516
794
      if ( !readToken( comma )
517
794
            ||  ( comma.type_ != tokenObjectEnd  &&  
518
794
                  
comma.type_ != tokenArraySeparator513
&&
519
794
      
comma.type_ != tokenComment0
) )
520
0
      {
521
0
         return addErrorAndRecover( "Missing ',' or '}' in object declaration", 
522
0
                                    comma, 
523
0
                                    tokenObjectEnd );
524
0
      }
525
794
      bool finalizeTokenOk = true;
526
794
      while ( comma.type_ == tokenComment &&
527
794
              
finalizeTokenOk0
)
528
794
         
finalizeTokenOk = readToken( comma )0
;
529
794
      if ( comma.type_ == tokenObjectEnd )
530
281
         return true;
531
794
   }
532
281
   return addErrorAndRecover( "Missing '}' or object member name", 
533
0
                              tokenName, 
534
0
                              tokenObjectEnd );
535
281
}
536
537
538
bool 
539
Reader::readArray( Token &tokenStart )
540
171
{
541
171
   currentValue() = Value( arrayValue );
542
171
   skipSpaces();
543
171
   if ( *current_ == ']' ) // empty array
544
0
   {
545
0
      Token endArray;
546
0
      readToken( endArray );
547
0
      return true;
548
0
   }
549
171
   int index = 0;
550
303
   while ( true )
551
303
   {
552
303
      Value &value = currentValue()[ index++ ];
553
303
      nodes_.push( &value );
554
303
      bool ok = readValue();
555
303
      nodes_.pop();
556
303
      if ( !ok ) // error already set
557
0
         return recoverFromError( tokenArrayEnd );
558
303
559
303
      Token token;
560
303
      // Accept Comment after last item in the array.
561
303
      ok = readToken( token );
562
303
      while ( token.type_ == tokenComment  &&  
ok0
)
563
303
      {
564
0
         ok = readToken( token );
565
0
      }
566
303
      bool badTokenType = ( token.type_ == tokenArraySeparator  &&  
567
303
                            
token.type_ == tokenArrayEnd132
);
568
303
      if ( !ok  ||  badTokenType )
569
0
      {
570
0
         return addErrorAndRecover( "Missing ',' or ']' in array declaration", 
571
0
                                    token, 
572
0
                                    tokenArrayEnd );
573
0
      }
574
303
      if ( token.type_ == tokenArrayEnd )
575
171
         break;
576
303
   }
577
171
   return true;
578
171
}
579
580
581
bool 
582
Reader::decodeNumber( Token &token )
583
0
{
584
0
   bool isDouble = false;
585
0
   for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
586
0
   {
587
0
      isDouble = isDouble  
588
0
                 ||  in( *inspect, '.', 'e', 'E', '+' )  
589
0
                 ||  ( *inspect == '-'  &&  inspect != token.start_ );
590
0
   }
591
0
   if ( isDouble )
592
0
      return decodeDouble( token );
593
0
   Location current = token.start_;
594
0
   bool isNegative = *current == '-';
595
0
   if ( isNegative )
596
0
      ++current;
597
0
   Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) 
598
0
                                       : Value::maxUInt) / 10;
599
0
   Value::UInt value = 0;
600
0
   while ( current < token.end_ )
601
0
   {
602
0
      Char c = *current++;
603
0
      if ( c < '0'  ||  c > '9' )
604
0
         return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
605
0
      if ( value >= threshold )
606
0
         return decodeDouble( token );
607
0
      value = value * 10 + Value::UInt(c - '0');
608
0
   }
609
0
   if ( isNegative )
610
0
      currentValue() = -Value::Int( value );
611
0
   else if ( value <= Value::UInt(Value::maxInt) )
612
0
      currentValue() = Value::Int( value );
613
0
   else
614
0
      currentValue() = value;
615
0
   return true;
616
0
}
617
618
619
bool 
620
Reader::decodeDouble( Token &token )
621
0
{
622
0
   double value = 0;
623
0
   const int bufferSize = 32;
624
0
   int count;
625
0
   int length = int(token.end_ - token.start_);
626
0
   if ( length <= bufferSize )
627
0
   {
628
0
      Char buffer[bufferSize];
629
0
      memcpy( buffer, token.start_, length );
630
0
      buffer[length] = 0;
631
0
      count = sscanf( buffer, "%lf", &value );
632
0
   }
633
0
   else
634
0
   {
635
0
      std::string buffer( token.start_, token.end_ );
636
0
      count = sscanf( buffer.c_str(), "%lf", &value );
637
0
   }
638
0
639
0
   if ( count != 1 )
640
0
      return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
641
0
   currentValue() = value;
642
0
   return true;
643
0
}
644
645
646
bool 
647
Reader::decodeString( Token &token )
648
684
{
649
684
   std::string decoded;
650
684
   if ( !decodeString( token, decoded ) )
651
0
      return false;
652
684
   currentValue() = decoded;
653
684
   return true;
654
684
}
655
656
657
bool 
658
Reader::decodeString( Token &token, std::string &decoded )
659
1.47k
{
660
1.47k
   decoded.reserve( token.end_ - token.start_ - 2 );
661
1.47k
   Location current = token.start_ + 1; // skip '"'
662
1.47k
   Location end = token.end_ - 1;      // do not include '"'
663
22.5k
   while ( current != end )
664
21.0k
   {
665
21.0k
      Char c = *current++;
666
21.0k
      if ( c == '"' )
667
0
         break;
668
21.0k
      else if ( c == '\\' )
669
0
      {
670
0
         if ( current == end )
671
0
            return addError( "Empty escape sequence in string", token, current );
672
0
         Char escape = *current++;
673
0
         switch ( escape )
674
0
         {
675
0
         case '"': decoded += '"'; break;
676
0
         case '/': decoded += '/'; break;
677
0
         case '\\': decoded += '\\'; break;
678
0
         case 'b': decoded += '\b'; break;
679
0
         case 'f': decoded += '\f'; break;
680
0
         case 'n': decoded += '\n'; break;
681
0
         case 'r': decoded += '\r'; break;
682
0
         case 't': decoded += '\t'; break;
683
0
         case 'u':
684
0
            {
685
0
               unsigned int unicode;
686
0
               if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
687
0
                  return false;
688
0
               decoded += codePointToUTF8(unicode);
689
0
            }
690
0
            break;
691
0
         default:
692
0
            return addError( "Bad escape sequence in string", token, current );
693
21.0k
         }
694
21.0k
      }
695
21.0k
      else
696
21.0k
      {
697
21.0k
         decoded += c;
698
21.0k
      }
699
21.0k
   }
700
1.47k
   return true;
701
1.47k
}
702
703
bool
704
Reader::decodeUnicodeCodePoint( Token &token, 
705
                                     Location &current, 
706
                                     Location end, 
707
                                     unsigned int &unicode )
708
0
{
709
0
710
0
   if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
711
0
      return false;
712
0
   if (unicode >= 0xD800 && unicode <= 0xDBFF)
713
0
   {
714
0
      // surrogate pairs
715
0
      if (end - current < 6)
716
0
         return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
717
0
      unsigned int surrogatePair;
718
0
      if (*(current++) == '\\' && *(current++)== 'u')
719
0
      {
720
0
         if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
721
0
         {
722
0
            unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
723
0
         } 
724
0
         else
725
0
            return false;
726
0
      } 
727
0
      else
728
0
         return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
729
0
   }
730
0
   return true;
731
0
}
732
733
bool 
734
Reader::decodeUnicodeEscapeSequence( Token &token, 
735
                                     Location &current, 
736
                                     Location end, 
737
                                     unsigned int &unicode )
738
0
{
739
0
   if ( end - current < 4 )
740
0
      return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
741
0
   unicode = 0;
742
0
   for ( int index =0; index < 4; ++index )
743
0
   {
744
0
      Char c = *current++;
745
0
      unicode *= 16;
746
0
      if ( c >= '0'  &&  c <= '9' )
747
0
         unicode += c - '0';
748
0
      else if ( c >= 'a'  &&  c <= 'f' )
749
0
         unicode += c - 'a' + 10;
750
0
      else if ( c >= 'A'  &&  c <= 'F' )
751
0
         unicode += c - 'A' + 10;
752
0
      else
753
0
         return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
754
0
   }
755
0
   return true;
756
0
}
757
758
759
bool 
760
Reader::addError( const std::string &message, 
761
                  Token &token,
762
                  Location extra )
763
0
{
764
0
   ErrorInfo info;
765
0
   info.token_ = token;
766
0
   info.message_ = message;
767
0
   info.extra_ = extra;
768
0
   errors_.push_back( info );
769
0
   return false;
770
0
}
771
772
773
bool 
774
Reader::recoverFromError( TokenType skipUntilToken )
775
0
{
776
0
   int errorCount = int(errors_.size());
777
0
   Token skip;
778
0
   while ( true )
779
0
   {
780
0
      if ( !readToken(skip) )
781
0
         errors_.resize( errorCount ); // discard errors caused by recovery
782
0
      if ( skip.type_ == skipUntilToken  ||  skip.type_ == tokenEndOfStream )
783
0
         break;
784
0
   }
785
0
   errors_.resize( errorCount );
786
0
   return false;
787
0
}
788
789
790
bool 
791
Reader::addErrorAndRecover( const std::string &message, 
792
                            Token &token,
793
                            TokenType skipUntilToken )
794
0
{
795
0
   addError( message, token );
796
0
   return recoverFromError( skipUntilToken );
797
0
}
798
799
800
Value &
801
Reader::currentValue()
802
3.36k
{
803
3.36k
   return *(nodes_.top());
804
3.36k
}
805
806
807
Reader::Char 
808
Reader::getNextChar()
809
26.3k
{
810
26.3k
   if ( current_ == end_ )
811
39
      return 0;
812
26.3k
   return *current_++;
813
26.3k
}
814
815
816
void 
817
Reader::getLocationLineAndColumn( Location location,
818
                                  int &line,
819
                                  int &column ) const
820
0
{
821
0
   Location current = begin_;
822
0
   Location lastLineStart = current;
823
0
   line = 0;
824
0
   while ( current < location  &&  current != end_ )
825
0
   {
826
0
      Char c = *current++;
827
0
      if ( c == '\r' )
828
0
      {
829
0
         if ( *current == '\n' )
830
0
            ++current;
831
0
         lastLineStart = current;
832
0
         ++line;
833
0
      }
834
0
      else if ( c == '\n' )
835
0
      {
836
0
         lastLineStart = current;
837
0
         ++line;
838
0
      }
839
0
   }
840
0
   // column & line start at 1
841
0
   column = int(location - lastLineStart) + 1;
842
0
   ++line;
843
0
}
844
845
846
std::string
847
Reader::getLocationLineAndColumn( Location location ) const
848
0
{
849
0
   int line, column;
850
0
   getLocationLineAndColumn( location, line, column );
851
0
   char buffer[18+16+16+1];
852
0
   sprintf( buffer, "Line %d, Column %d", line, column );
853
0
   return buffer;
854
0
}
855
856
857
std::string 
858
Reader::getFormatedErrorMessages() const
859
0
{
860
0
   std::string formattedMessage;
861
0
   for ( Errors::const_iterator itError = errors_.begin();
862
0
         itError != errors_.end();
863
0
         ++itError )
864
0
   {
865
0
      const ErrorInfo &error = *itError;
866
0
      formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
867
0
      formattedMessage += "  " + error.message_ + "\n";
868
0
      if ( error.extra_ )
869
0
         formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
870
0
   }
871
0
   return formattedMessage;
872
0
}
873
874
875
std::istream& operator>>( std::istream &sin, Value &root )
876
0
{
877
0
    Json::Reader reader;
878
0
    bool ok = reader.parse(sin, root, true);
879
0
    //JSON_ASSERT( ok );
880
#if JSON_USE_EXCEPTION
881
    if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
882
#else
883
    assert(ok && "Bad Format!");
884
0
    (void) ok;
885
0
#endif
886
0
    return sin;
887
0
}
888
889
890
} // namespace Json