Drizzled Public API Documentation

json_reader.cpp
00001 /*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00002  * 
00003  *  JSON Library, originally from http://jsoncpp.sourceforge.net/
00004  *
00005  *  Copyright (C) 2011 Stewart Smith
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions are
00010  *  met:
00011  *
00012  *      * Redistributions of source code must retain the above copyright
00013  *  notice, this list of conditions and the following disclaimer.
00014  *
00015  *      * Redistributions in binary form must reproduce the above
00016  *  copyright notice, this list of conditions and the following disclaimer
00017  *  in the documentation and/or other materials provided with the
00018  *  distribution.
00019  *
00020  *      * The names of its contributors may not be used to endorse or
00021  *  promote products derived from this software without specific prior
00022  *  written permission.
00023  *
00024  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00025  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00026  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00027  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00028  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00029  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00030  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00031  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00032  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00033  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00034  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  */
00037 
00038 #include <config.h>
00039 
00040 #include <plugin/json_server/json/reader.h>
00041 #include <plugin/json_server/json/value.h>
00042 
00043 #include <cassert>
00044 #include <cstdio>
00045 #include <cstring>
00046 #include <iostream>
00047 #include <stdexcept>
00048 #include <utility>
00049 
00050 namespace Json {
00051 
00052 // Implementation of class Features
00053 // ////////////////////////////////
00054 
00055 Features::Features()
00056    : allowComments_( true )
00057    , strictRoot_( false )
00058 {
00059 }
00060 
00061 
00062 Features 
00063 Features::all()
00064 {
00065    return Features();
00066 }
00067 
00068 
00069 Features 
00070 Features::strictMode()
00071 {
00072    Features features;
00073    features.allowComments_ = false;
00074    features.strictRoot_ = true;
00075    return features;
00076 }
00077 
00078 // Implementation of class Reader
00079 // ////////////////////////////////
00080 
00081 
00082 static inline bool 
00083 in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
00084 {
00085    return c == c1  ||  c == c2  ||  c == c3  ||  c == c4;
00086 }
00087 
00088 static inline bool 
00089 in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
00090 {
00091    return c == c1  ||  c == c2  ||  c == c3  ||  c == c4  ||  c == c5;
00092 }
00093 
00094 
00095 static bool 
00096 containsNewLine( Reader::Location begin, 
00097                  Reader::Location end )
00098 {
00099    for ( ;begin < end; ++begin )
00100       if ( *begin == '\n'  ||  *begin == '\r' )
00101          return true;
00102    return false;
00103 }
00104 
00105 static std::string codePointToUTF8(unsigned int cp)
00106 {
00107    std::string result;
00108    
00109    // based on description from http://en.wikipedia.org/wiki/UTF-8
00110 
00111    if (cp <= 0x7f) 
00112    {
00113       result.resize(1);
00114       result[0] = static_cast<char>(cp);
00115    } 
00116    else if (cp <= 0x7FF) 
00117    {
00118       result.resize(2);
00119       result[1] = static_cast<char>(0x80 | (0x3f & cp));
00120       result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
00121    } 
00122    else if (cp <= 0xFFFF) 
00123    {
00124       result.resize(3);
00125       result[2] = static_cast<char>(0x80 | (0x3f & cp));
00126       result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
00127       result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
00128    }
00129    else if (cp <= 0x10FFFF) 
00130    {
00131       result.resize(4);
00132       result[3] = static_cast<char>(0x80 | (0x3f & cp));
00133       result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
00134       result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
00135       result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
00136    }
00137 
00138    return result;
00139 }
00140 
00141 
00142 // Class Reader
00143 // //////////////////////////////////////////////////////////////////
00144 
00145 Reader::Reader()
00146    : features_( Features::all() )
00147 {
00148 }
00149 
00150 
00151 Reader::Reader( const Features &features )
00152    : features_( features )
00153 {
00154 }
00155 
00156 
00157 bool
00158 Reader::parse( const std::string &document, 
00159                Value &root,
00160                bool collectComments )
00161 {
00162    document_ = document;
00163    const char *begin = document_.c_str();
00164    const char *end = begin + document_.length();
00165    return parse( begin, end, root, collectComments );
00166 }
00167 
00168 
00169 bool
00170 Reader::parse( std::istream& sin,
00171                Value &root,
00172                bool collectComments )
00173 {
00174    //std::istream_iterator<char> begin(sin);
00175    //std::istream_iterator<char> end;
00176    // Those would allow streamed input from a file, if parse() were a
00177    // template function.
00178 
00179    // Since std::string is reference-counted, this at least does not
00180    // create an extra copy.
00181    std::string doc;
00182    std::getline(sin, doc, (char)EOF);
00183    return parse( doc, root, collectComments );
00184 }
00185 
00186 bool 
00187 Reader::parse( const char *beginDoc, const char *endDoc, 
00188                Value &root,
00189                bool collectComments )
00190 {
00191    if ( !features_.allowComments_ )
00192    {
00193       collectComments = false;
00194    }
00195 
00196    begin_ = beginDoc;
00197    end_ = endDoc;
00198    collectComments_ = collectComments;
00199    current_ = begin_;
00200    lastValueEnd_ = 0;
00201    lastValue_ = 0;
00202    commentsBefore_ = "";
00203    errors_.clear();
00204    while ( !nodes_.empty() )
00205       nodes_.pop();
00206    nodes_.push( &root );
00207    
00208    bool successful = readValue();
00209    Token token;
00210    skipCommentTokens( token );
00211    if ( collectComments_  &&  !commentsBefore_.empty() )
00212       root.setComment( commentsBefore_, commentAfter );
00213    if ( features_.strictRoot_ )
00214    {
00215       if ( !root.isArray()  &&  !root.isObject() )
00216       {
00217          // Set error location to start of doc, ideally should be first token found in doc
00218          token.type_ = tokenError;
00219          token.start_ = beginDoc;
00220          token.end_ = endDoc;
00221          addError( "A valid JSON document must be either an array or an object value.",
00222                    token );
00223          return false;
00224       }
00225    }
00226    return successful;
00227 }
00228 
00229 
00230 bool
00231 Reader::readValue()
00232 {
00233    Token token;
00234    skipCommentTokens( token );
00235    bool successful = true;
00236 
00237    if ( collectComments_  &&  !commentsBefore_.empty() )
00238    {
00239       currentValue().setComment( commentsBefore_, commentBefore );
00240       commentsBefore_ = "";
00241    }
00242 
00243 
00244    switch ( token.type_ )
00245    {
00246    case tokenObjectBegin:
00247       successful = readObject( token );
00248       break;
00249    case tokenArrayBegin:
00250       successful = readArray( token );
00251       break;
00252    case tokenNumber:
00253       successful = decodeNumber( token );
00254       break;
00255    case tokenString:
00256       successful = decodeString( token );
00257       break;
00258    case tokenTrue:
00259       currentValue() = true;
00260       break;
00261    case tokenFalse:
00262       currentValue() = false;
00263       break;
00264    case tokenNull:
00265       currentValue() = Value();
00266       break;
00267    default:
00268       return addError( "Syntax error: value, object or array expected.", token );
00269    }
00270 
00271    if ( collectComments_ )
00272    {
00273       lastValueEnd_ = current_;
00274       lastValue_ = &currentValue();
00275    }
00276 
00277    return successful;
00278 }
00279 
00280 
00281 void 
00282 Reader::skipCommentTokens( Token &token )
00283 {
00284    if ( features_.allowComments_ )
00285    {
00286       do
00287       {
00288          readToken( token );
00289       }
00290       while ( token.type_ == tokenComment );
00291    }
00292    else
00293    {
00294       readToken( token );
00295    }
00296 }
00297 
00298 
00299 bool 
00300 Reader::expectToken( TokenType type, Token &token, const char *message )
00301 {
00302    readToken( token );
00303    if ( token.type_ != type )
00304       return addError( message, token );
00305    return true;
00306 }
00307 
00308 
00309 bool 
00310 Reader::readToken( Token &token )
00311 {
00312    skipSpaces();
00313    token.start_ = current_;
00314    Char c = getNextChar();
00315    bool ok = true;
00316    switch ( c )
00317    {
00318    case '{':
00319       token.type_ = tokenObjectBegin;
00320       break;
00321    case '}':
00322       token.type_ = tokenObjectEnd;
00323       break;
00324    case '[':
00325       token.type_ = tokenArrayBegin;
00326       break;
00327    case ']':
00328       token.type_ = tokenArrayEnd;
00329       break;
00330    case '"':
00331       token.type_ = tokenString;
00332       ok = readString();
00333       break;
00334    case '/':
00335       token.type_ = tokenComment;
00336       ok = readComment();
00337       break;
00338    case '0':
00339    case '1':
00340    case '2':
00341    case '3':
00342    case '4':
00343    case '5':
00344    case '6':
00345    case '7':
00346    case '8':
00347    case '9':
00348    case '-':
00349       token.type_ = tokenNumber;
00350       readNumber();
00351       break;
00352    case 't':
00353       token.type_ = tokenTrue;
00354       ok = match( "rue", 3 );
00355       break;
00356    case 'f':
00357       token.type_ = tokenFalse;
00358       ok = match( "alse", 4 );
00359       break;
00360    case 'n':
00361       token.type_ = tokenNull;
00362       ok = match( "ull", 3 );
00363       break;
00364    case ',':
00365       token.type_ = tokenArraySeparator;
00366       break;
00367    case ':':
00368       token.type_ = tokenMemberSeparator;
00369       break;
00370    case 0:
00371       token.type_ = tokenEndOfStream;
00372       break;
00373    default:
00374       ok = false;
00375       break;
00376    }
00377    if ( !ok )
00378       token.type_ = tokenError;
00379    token.end_ = current_;
00380    return true;
00381 }
00382 
00383 
00384 void 
00385 Reader::skipSpaces()
00386 {
00387    while ( current_ != end_ )
00388    {
00389       Char c = *current_;
00390       if ( c == ' '  ||  c == '\t'  ||  c == '\r'  ||  c == '\n' )
00391          ++current_;
00392       else
00393          break;
00394    }
00395 }
00396 
00397 
00398 bool 
00399 Reader::match( Location pattern, 
00400                int patternLength )
00401 {
00402    if ( end_ - current_ < patternLength )
00403       return false;
00404    int index = patternLength;
00405    while ( index-- )
00406       if ( current_[index] != pattern[index] )
00407          return false;
00408    current_ += patternLength;
00409    return true;
00410 }
00411 
00412 
00413 bool
00414 Reader::readComment()
00415 {
00416    Location commentBegin = current_ - 1;
00417    Char c = getNextChar();
00418    bool successful = false;
00419    if ( c == '*' )
00420       successful = readCStyleComment();
00421    else if ( c == '/' )
00422       successful = readCppStyleComment();
00423    if ( !successful )
00424       return false;
00425 
00426    if ( collectComments_ )
00427    {
00428       CommentPlacement placement = commentBefore;
00429       if ( lastValueEnd_  &&  !containsNewLine( lastValueEnd_, commentBegin ) )
00430       {
00431          if ( c != '*'  ||  !containsNewLine( commentBegin, current_ ) )
00432             placement = commentAfterOnSameLine;
00433       }
00434 
00435       addComment( commentBegin, current_, placement );
00436    }
00437    return true;
00438 }
00439 
00440 
00441 void 
00442 Reader::addComment( Location begin, 
00443                     Location end, 
00444                     CommentPlacement placement )
00445 {
00446    assert( collectComments_ );
00447    if ( placement == commentAfterOnSameLine )
00448    {
00449       assert( lastValue_ != 0 );
00450       lastValue_->setComment( std::string( begin, end ), placement );
00451    }
00452    else
00453    {
00454       if ( !commentsBefore_.empty() )
00455          commentsBefore_ += "\n";
00456       commentsBefore_ += std::string( begin, end );
00457    }
00458 }
00459 
00460 
00461 bool 
00462 Reader::readCStyleComment()
00463 {
00464    while ( current_ != end_ )
00465    {
00466       Char c = getNextChar();
00467       if ( c == '*'  &&  *current_ == '/' )
00468          break;
00469    }
00470    return getNextChar() == '/';
00471 }
00472 
00473 
00474 bool 
00475 Reader::readCppStyleComment()
00476 {
00477    while ( current_ != end_ )
00478    {
00479       Char c = getNextChar();
00480       if (  c == '\r'  ||  c == '\n' )
00481          break;
00482    }
00483    return true;
00484 }
00485 
00486 
00487 void 
00488 Reader::readNumber()
00489 {
00490    while ( current_ != end_ )
00491    {
00492       if ( !(*current_ >= '0'  &&  *current_ <= '9')  &&
00493            !in( *current_, '.', 'e', 'E', '+', '-' ) )
00494          break;
00495       ++current_;
00496    }
00497 }
00498 
00499 bool
00500 Reader::readString()
00501 {
00502    Char c = 0;
00503    while ( current_ != end_ )
00504    {
00505       c = getNextChar();
00506       if ( c == '\\' )
00507          getNextChar();
00508       else if ( c == '"' )
00509          break;
00510    }
00511    return c == '"';
00512 }
00513 
00514 
00515 bool 
00516 Reader::readObject( Token & )
00517 {
00518    Token tokenName;
00519    std::string name;
00520    currentValue() = Value( objectValue );
00521    while ( readToken( tokenName ) )
00522    {
00523       bool initialTokenOk = true;
00524       while ( tokenName.type_ == tokenComment  &&  initialTokenOk )
00525          initialTokenOk = readToken( tokenName );
00526       if  ( !initialTokenOk )
00527          break;
00528       if ( tokenName.type_ == tokenObjectEnd  &&  name.empty() )  // empty object
00529          return true;
00530       if ( tokenName.type_ != tokenString )
00531          break;
00532       
00533       name = "";
00534       if ( !decodeString( tokenName, name ) )
00535          return recoverFromError( tokenObjectEnd );
00536 
00537       Token colon;
00538       if ( !readToken( colon ) ||  colon.type_ != tokenMemberSeparator )
00539       {
00540          return addErrorAndRecover( "Missing ':' after object member name", 
00541                                     colon, 
00542                                     tokenObjectEnd );
00543       }
00544       Value &value = currentValue()[ name ];
00545       nodes_.push( &value );
00546       bool ok = readValue();
00547       nodes_.pop();
00548       if ( !ok ) // error already set
00549          return recoverFromError( tokenObjectEnd );
00550 
00551       Token comma;
00552       if ( !readToken( comma )
00553             ||  ( comma.type_ != tokenObjectEnd  &&  
00554                   comma.type_ != tokenArraySeparator &&
00555       comma.type_ != tokenComment ) )
00556       {
00557          return addErrorAndRecover( "Missing ',' or '}' in object declaration", 
00558                                     comma, 
00559                                     tokenObjectEnd );
00560       }
00561       bool finalizeTokenOk = true;
00562       while ( comma.type_ == tokenComment &&
00563               finalizeTokenOk )
00564          finalizeTokenOk = readToken( comma );
00565       if ( comma.type_ == tokenObjectEnd )
00566          return true;
00567    }
00568    return addErrorAndRecover( "Missing '}' or object member name", 
00569                               tokenName, 
00570                               tokenObjectEnd );
00571 }
00572 
00573 
00574 bool 
00575 Reader::readArray( Token & )
00576 {
00577    currentValue() = Value( arrayValue );
00578    skipSpaces();
00579    if ( *current_ == ']' ) // empty array
00580    {
00581       Token endArray;
00582       readToken( endArray );
00583       return true;
00584    }
00585    int index = 0;
00586    while ( true )
00587    {
00588       Value &value = currentValue()[ index++ ];
00589       nodes_.push( &value );
00590       bool ok = readValue();
00591       nodes_.pop();
00592       if ( !ok ) // error already set
00593          return recoverFromError( tokenArrayEnd );
00594 
00595       Token token;
00596       // Accept Comment after last item in the array.
00597       ok = readToken( token );
00598       while ( token.type_ == tokenComment  &&  ok )
00599       {
00600          ok = readToken( token );
00601       }
00602       bool badTokenType = ( token.type_ == tokenArraySeparator  &&  
00603                             token.type_ == tokenArrayEnd );
00604       if ( !ok  ||  badTokenType )
00605       {
00606          return addErrorAndRecover( "Missing ',' or ']' in array declaration", 
00607                                     token, 
00608                                     tokenArrayEnd );
00609       }
00610       if ( token.type_ == tokenArrayEnd )
00611          break;
00612    }
00613    return true;
00614 }
00615 
00616 
00617 bool 
00618 Reader::decodeNumber( Token &token )
00619 {
00620    bool isDouble = false;
00621    for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
00622    {
00623       isDouble = isDouble  
00624                  ||  in( *inspect, '.', 'e', 'E', '+' )  
00625                  ||  ( *inspect == '-'  &&  inspect != token.start_ );
00626    }
00627    if ( isDouble )
00628       return decodeDouble( token );
00629    Location current = token.start_;
00630    bool isNegative = *current == '-';
00631    if ( isNegative )
00632       ++current;
00633    Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) 
00634                                        : Value::maxUInt) / 10;
00635    Value::UInt value = 0;
00636    while ( current < token.end_ )
00637    {
00638       Char c = *current++;
00639       if ( c < '0'  ||  c > '9' )
00640          return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
00641       if ( value >= threshold )
00642          return decodeDouble( token );
00643       value = value * 10 + Value::UInt(c - '0');
00644    }
00645    if ( isNegative )
00646       currentValue() = -Value::Int( value );
00647    else if ( value <= Value::UInt(Value::maxInt) )
00648       currentValue() = Value::Int( value );
00649    else
00650       currentValue() = value;
00651    return true;
00652 }
00653 
00654 
00655 bool 
00656 Reader::decodeDouble( Token &token )
00657 {
00658    double value = 0;
00659    const int bufferSize = 32;
00660    int count;
00661    int length = int(token.end_ - token.start_);
00662    if ( length <= bufferSize )
00663    {
00664       Char buffer[bufferSize];
00665       memcpy( buffer, token.start_, length );
00666       buffer[length] = 0;
00667       count = sscanf( buffer, "%lf", &value );
00668    }
00669    else
00670    {
00671       std::string buffer( token.start_, token.end_ );
00672       count = sscanf( buffer.c_str(), "%lf", &value );
00673    }
00674 
00675    if ( count != 1 )
00676       return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
00677    currentValue() = value;
00678    return true;
00679 }
00680 
00681 
00682 bool 
00683 Reader::decodeString( Token &token )
00684 {
00685    std::string decoded;
00686    if ( !decodeString( token, decoded ) )
00687       return false;
00688    currentValue() = decoded;
00689    return true;
00690 }
00691 
00692 
00693 bool 
00694 Reader::decodeString( Token &token, std::string &decoded )
00695 {
00696    decoded.reserve( token.end_ - token.start_ - 2 );
00697    Location current = token.start_ + 1; // skip '"'
00698    Location end = token.end_ - 1;      // do not include '"'
00699    while ( current != end )
00700    {
00701       Char c = *current++;
00702       if ( c == '"' )
00703          break;
00704       else if ( c == '\\' )
00705       {
00706          if ( current == end )
00707             return addError( "Empty escape sequence in string", token, current );
00708          Char escape = *current++;
00709          switch ( escape )
00710          {
00711          case '"': decoded += '"'; break;
00712          case '/': decoded += '/'; break;
00713          case '\\': decoded += '\\'; break;
00714          case 'b': decoded += '\b'; break;
00715          case 'f': decoded += '\f'; break;
00716          case 'n': decoded += '\n'; break;
00717          case 'r': decoded += '\r'; break;
00718          case 't': decoded += '\t'; break;
00719          case 'u':
00720             {
00721                unsigned int unicode;
00722                if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
00723                   return false;
00724                decoded += codePointToUTF8(unicode);
00725             }
00726             break;
00727          default:
00728             return addError( "Bad escape sequence in string", token, current );
00729          }
00730       }
00731       else
00732       {
00733          decoded += c;
00734       }
00735    }
00736    return true;
00737 }
00738 
00739 bool
00740 Reader::decodeUnicodeCodePoint( Token &token, 
00741                                      Location &current, 
00742                                      Location end, 
00743                                      unsigned int &unicode )
00744 {
00745 
00746    if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
00747       return false;
00748    if (unicode >= 0xD800 && unicode <= 0xDBFF)
00749    {
00750       // surrogate pairs
00751       if (end - current < 6)
00752          return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
00753       unsigned int surrogatePair;
00754       if (*(current++) == '\\' && *(current++)== 'u')
00755       {
00756          if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
00757          {
00758             unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
00759          } 
00760          else
00761             return false;
00762       } 
00763       else
00764          return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
00765    }
00766    return true;
00767 }
00768 
00769 bool 
00770 Reader::decodeUnicodeEscapeSequence( Token &token, 
00771                                      Location &current, 
00772                                      Location end, 
00773                                      unsigned int &unicode )
00774 {
00775    if ( end - current < 4 )
00776       return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
00777    unicode = 0;
00778    for ( int index =0; index < 4; ++index )
00779    {
00780       Char c = *current++;
00781       unicode *= 16;
00782       if ( c >= '0'  &&  c <= '9' )
00783          unicode += c - '0';
00784       else if ( c >= 'a'  &&  c <= 'f' )
00785          unicode += c - 'a' + 10;
00786       else if ( c >= 'A'  &&  c <= 'F' )
00787          unicode += c - 'A' + 10;
00788       else
00789          return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
00790    }
00791    return true;
00792 }
00793 
00794 
00795 bool 
00796 Reader::addError( const std::string &message, 
00797                   Token &token,
00798                   Location extra )
00799 {
00800    ErrorInfo info;
00801    info.token_ = token;
00802    info.message_ = message;
00803    info.extra_ = extra;
00804    errors_.push_back( info );
00805    return false;
00806 }
00807 
00808 
00809 bool 
00810 Reader::recoverFromError( TokenType skipUntilToken )
00811 {
00812    int errorCount = int(errors_.size());
00813    Token skip;
00814    while ( true )
00815    {
00816       if ( !readToken(skip) )
00817          errors_.resize( errorCount ); // discard errors caused by recovery
00818       if ( skip.type_ == skipUntilToken  ||  skip.type_ == tokenEndOfStream )
00819          break;
00820    }
00821    errors_.resize( errorCount );
00822    return false;
00823 }
00824 
00825 
00826 bool 
00827 Reader::addErrorAndRecover( const std::string &message, 
00828                             Token &token,
00829                             TokenType skipUntilToken )
00830 {
00831    addError( message, token );
00832    return recoverFromError( skipUntilToken );
00833 }
00834 
00835 
00836 Value &
00837 Reader::currentValue()
00838 {
00839    return *(nodes_.top());
00840 }
00841 
00842 
00843 Reader::Char 
00844 Reader::getNextChar()
00845 {
00846    if ( current_ == end_ )
00847       return 0;
00848    return *current_++;
00849 }
00850 
00851 
00852 void 
00853 Reader::getLocationLineAndColumn( Location location,
00854                                   int &line,
00855                                   int &column ) const
00856 {
00857    Location current = begin_;
00858    Location lastLineStart = current;
00859    line = 0;
00860    while ( current < location  &&  current != end_ )
00861    {
00862       Char c = *current++;
00863       if ( c == '\r' )
00864       {
00865          if ( *current == '\n' )
00866             ++current;
00867          lastLineStart = current;
00868          ++line;
00869       }
00870       else if ( c == '\n' )
00871       {
00872          lastLineStart = current;
00873          ++line;
00874       }
00875    }
00876    // column & line start at 1
00877    column = int(location - lastLineStart) + 1;
00878    ++line;
00879 }
00880 
00881 
00882 std::string
00883 Reader::getLocationLineAndColumn( Location location ) const
00884 {
00885    int line, column;
00886    getLocationLineAndColumn( location, line, column );
00887    char buffer[18+16+16+1];
00888    sprintf( buffer, "Line %d, Column %d", line, column );
00889    return buffer;
00890 }
00891 
00892 
00893 std::string 
00894 Reader::getFormatedErrorMessages() const
00895 {
00896    std::string formattedMessage;
00897    for ( Errors::const_iterator itError = errors_.begin();
00898          itError != errors_.end();
00899          ++itError )
00900    {
00901       const ErrorInfo &error = *itError;
00902       formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
00903       formattedMessage += "  " + error.message_ + "\n";
00904       if ( error.extra_ )
00905          formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
00906    }
00907    return formattedMessage;
00908 }
00909 
00910 
00911 std::istream& operator>>( std::istream &sin, Value &root )
00912 {
00913     Json::Reader reader;
00914     bool ok = reader.parse(sin, root, true);
00915     //JSON_ASSERT( ok );
00916     if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
00917     return sin;
00918 }
00919 
00920 
00921 } // namespace Json