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