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