00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
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
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
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
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
00175
00176
00177
00178
00179
00180
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
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_ = ¤tValue();
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() )
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 )
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_ == ']' )
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 )
00593 return recoverFromError( tokenArrayEnd );
00594
00595 Token token;
00596
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;
00698 Location end = token.end_ - 1;
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 ¤t,
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
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 ¤t,
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 );
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
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
00916 if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
00917 return sin;
00918 }
00919
00920
00921 }