Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

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