![]() |
RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
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_ = ¤tValue(); 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 ¤t, 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 ¤t, 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