osgEarth 2.1.1
|
Unserialize a JSON document into a Value. More...
Classes | |
class | ErrorInfo |
class | Token |
Public Types | |
typedef char | Char |
typedef const Char * | Location |
Public Member Functions | |
Reader () | |
bool | parse (const std::string &document, Value &root, bool collectComments=true) |
Read a Value from a JSON document. | |
bool | parse (const char *beginDoc, const char *endDoc, Value &root, bool collectComments=true) |
Read a Value from a JSON document. | |
bool | parse (std::istream &, Value &root, bool collectComments=true) |
Parse from input stream. | |
std::string | getFormatedErrorMessages () const |
Returns a user friendly string that list errors in the parsed document. | |
Private Types | |
enum | TokenType { tokenEndOfStream = 0, tokenObjectBegin, tokenObjectEnd, tokenArrayBegin, tokenArrayEnd, tokenString, tokenNumber, tokenTrue, tokenFalse, tokenNull, tokenArraySeparator, tokenMemberSeparator, tokenComment, tokenError } |
typedef std::deque< ErrorInfo > | Errors |
typedef std::stack< Value * > | Nodes |
Private Member Functions | |
bool | expectToken (TokenType type, Token &token, const char *message) |
bool | readToken (Token &token) |
void | skipSpaces () |
bool | match (Location pattern, int patternLength) |
bool | readComment () |
bool | readCStyleComment () |
bool | readCppStyleComment () |
bool | readString () |
void | readNumber () |
bool | readValue () |
bool | readObject (Token &token) |
bool | readArray (Token &token) |
bool | decodeNumber (Token &token) |
bool | decodeString (Token &token) |
bool | decodeString (Token &token, std::string &decoded) |
bool | decodeDouble (Token &token) |
bool | decodeUnicodeEscapeSequence (Token &token, Location ¤t, Location end, unsigned int &unicode) |
bool | addError (const std::string &message, Token &token, Location extra=0) |
bool | recoverFromError (TokenType skipUntilToken) |
bool | addErrorAndRecover (const std::string &message, Token &token, TokenType skipUntilToken) |
void | skipUntilSpace () |
Value & | currentValue () |
Char | getNextChar () |
void | getLocationLineAndColumn (Location location, int &line, int &column) const |
std::string | getLocationLineAndColumn (Location location) const |
void | addComment (Location begin, Location end, CommentPlacement placement) |
void | skipCommentTokens (Token &token) |
Private Attributes | |
Nodes | nodes_ |
Errors | errors_ |
std::string | document_ |
Location | begin_ |
Location | end_ |
Location | current_ |
Location | lastValueEnd_ |
Value * | lastValue_ |
std::string | commentsBefore_ |
bool | collectComments_ |
typedef char osgEarth::Json::Reader::Char |
typedef std::deque<ErrorInfo> osgEarth::Json::Reader::Errors [private] |
typedef const Char* osgEarth::Json::Reader::Location |
typedef std::stack<Value *> osgEarth::Json::Reader::Nodes [private] |
enum osgEarth::Json::Reader::TokenType [private] |
Reader::Reader | ( | ) |
Definition at line 2019 of file JsonUtils.cpp.
{ }
void Reader::addComment | ( | Location | begin, |
Location | end, | ||
CommentPlacement | placement | ||
) | [private] |
Definition at line 2284 of file JsonUtils.cpp.
{ assert( collectComments_ ); if ( placement == commentAfterOnSameLine ) { assert( lastValue_ != 0 ); lastValue_->setComment( std::string( begin, end ), placement ); } else { if ( !commentsBefore_.empty() ) commentsBefore_ += "\n"; commentsBefore_ += std::string( begin, end ); } }
Definition at line 2604 of file JsonUtils.cpp.
{ ErrorInfo info; info.token_ = token; info.message_ = message; info.extra_ = extra; errors_.push_back( info ); return false; }
bool Reader::addErrorAndRecover | ( | const std::string & | message, |
Token & | token, | ||
TokenType | skipUntilToken | ||
) | [private] |
Definition at line 2635 of file JsonUtils.cpp.
{ addError( message, token ); return recoverFromError( skipUntilToken ); }
Value & Reader::currentValue | ( | ) | [private] |
Definition at line 2645 of file JsonUtils.cpp.
{ return *(nodes_.top()); }
bool Reader::decodeDouble | ( | Token & | token | ) | [private] |
Definition at line 2492 of file JsonUtils.cpp.
{ double value = 0; const int bufferSize = 32; int count; int length = int(token.end_ - token.start_); if ( length <= bufferSize ) { Char buffer[bufferSize]; memcpy( buffer, token.start_, length ); buffer[length] = 0; count = sscanf( buffer, "%lf", &value ); } else { std::string buffer( token.start_, token.end_ ); count = sscanf( buffer.c_str(), "%lf", &value ); } if ( count != 1 ) return addError( std::string("'") + std::string( token.start_, token.end_ ) + std::string("' is not a number."), token ); currentValue() = value; return true; }
bool Reader::decodeNumber | ( | Token & | token | ) | [private] |
Definition at line 2454 of file JsonUtils.cpp.
{ bool isDouble = false; for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) { isDouble = isDouble || in( *inspect, '.', 'e', 'E', '+' ) || ( *inspect == '-' && inspect != token.start_ ); } if ( isDouble ) return decodeDouble( token ); Location current = token.start_; bool isNegative = *current == '-'; if ( isNegative ) ++current; Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt) : Value::maxUInt) / 10; Value::UInt value = 0; while ( current < token.end_ ) { Char c = *current++; if ( c < '0' || c > '9' ) return addError( std::string("'") + std::string( token.start_, token.end_ ) + std::string("' is not a number."), token ); if ( value >= threshold ) return decodeDouble( token ); value = value * 10 + Value::UInt(c - '0'); } if ( isNegative ) currentValue() = -Value::Int( value ); else if ( value <= Value::UInt(Value::maxInt) ) currentValue() = Value::Int( value ); else currentValue() = value; return true; }
bool Reader::decodeString | ( | Token & | token, |
std::string & | decoded | ||
) | [private] |
Definition at line 2530 of file JsonUtils.cpp.
{ decoded.reserve( token.end_ - token.start_ - 2 ); Location current = token.start_ + 1; // skip '"' Location end = token.end_ - 1; // do not include '"' while ( current != end ) { Char c = *current++; if ( c == '"' ) break; else if ( c == '\\' ) { if ( current == end ) return addError( "Empty escape sequence in string", token, current ); Char escape = *current++; switch ( escape ) { case '"': decoded += '"'; break; case '/': decoded += '/'; break; case '\\': decoded += '\\'; break; case 'b': decoded += '\b'; break; case 'f': decoded += '\f'; break; case 'n': decoded += '\n'; break; case 'r': decoded += '\r'; break; case 't': decoded += '\t'; break; case 'u': { unsigned int unicode; if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) return false; // @todo encode unicode as utf8. // @todo remember to alter the writer too. } break; default: return addError( "Bad escape sequence in string", token, current ); } } else { decoded += c; } } return true; }
bool Reader::decodeString | ( | Token & | token | ) | [private] |
Definition at line 2519 of file JsonUtils.cpp.
{ std::string decoded; if ( !decodeString( token, decoded ) ) return false; currentValue() = decoded; return true; }
bool Reader::decodeUnicodeEscapeSequence | ( | Token & | token, |
Location & | current, | ||
Location | end, | ||
unsigned int & | unicode | ||
) | [private] |
Definition at line 2578 of file JsonUtils.cpp.
{ if ( end - current < 4 ) return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); unicode = 0; for ( int index =0; index < 4; ++index ) { Char c = *current++; unicode *= 16; if ( c >= '0' && c <= '9' ) unicode += c - '0'; else if ( c >= 'a' && c <= 'f' ) unicode += c - 'a' + 10; else if ( c >= 'A' && c <= 'F' ) unicode += c - 'A' + 10; else return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); } return true; }
std::string Reader::getFormatedErrorMessages | ( | ) | const |
Returns a user friendly string that list errors in the parsed document.
Definition at line 2702 of file JsonUtils.cpp.
{ std::string formattedMessage; for ( Errors::const_iterator itError = errors_.begin(); itError != errors_.end(); ++itError ) { const ErrorInfo &error = *itError; formattedMessage += std::string("* ") + getLocationLineAndColumn( error.token_.start_ ) + std::string("\n"); formattedMessage += std::string(" ") + error.message_ + std::string("\n"); if ( error.extra_ ) formattedMessage += std::string("See ") + getLocationLineAndColumn( error.extra_ ) + std::string(" for detail.\n"); } return formattedMessage; }
std::string Reader::getLocationLineAndColumn | ( | Location | location | ) | const [private] |
Definition at line 2691 of file JsonUtils.cpp.
{ int line, column; getLocationLineAndColumn( location, line, column ); char buffer[18+16+16+1]; sprintf( buffer, "Line %d, Column %d", line, column ); return buffer; }
void Reader::getLocationLineAndColumn | ( | Location | location, |
int & | line, | ||
int & | column | ||
) | const [private] |
Definition at line 2661 of file JsonUtils.cpp.
{ Location current = begin_; Location lastLineStart = current; line = 0; while ( current < location && current != end_ ) { Char c = *current++; if ( c == '\r' ) { if ( *current == '\n' ) ++current; lastLineStart = current; ++line; } else if ( c == '\n' ) { lastLineStart = current; ++line; } } // column & line start at 1 column = int(location - lastLineStart) + 1; ++line; }
Reader::Char Reader::getNextChar | ( | ) | [private] |
bool Reader::match | ( | Location | pattern, |
int | patternLength | ||
) | [private] |
bool Reader::parse | ( | const char * | beginDoc, |
const char * | endDoc, | ||
Value & | root, | ||
bool | collectComments = true |
||
) |
Read a Value from a JSON document.
document | UTF-8 encoded string containing the document to read. |
root | [out] Contains the root value of the document if it was successfully parsed. |
collectComments | true to collect comment and allow writing them back during serialization, false to discard comments. |
true
if the document was successfully parsed, false
if an error occurred. Definition at line 2052 of file JsonUtils.cpp.
{ begin_ = beginDoc; end_ = endDoc; collectComments_ = collectComments; current_ = begin_; lastValueEnd_ = 0; lastValue_ = 0; commentsBefore_ = ""; errors_.clear(); while ( !nodes_.empty() ) nodes_.pop(); nodes_.push( &root ); bool successful = readValue(); Token token; skipCommentTokens( token ); if ( collectComments_ && !commentsBefore_.empty() ) root.setComment( commentsBefore_, commentAfter ); return successful; }
bool Reader::parse | ( | const std::string & | document, |
Value & | root, | ||
bool | collectComments = true |
||
) |
Read a Value from a JSON document.
document | UTF-8 encoded string containing the document to read. |
root | [out] Contains the root value of the document if it was successfully parsed. |
collectComments | true to collect comment and allow writing them back during serialization, false to discard comments. |
true
if the document was successfully parsed, false
if an error occurred. Definition at line 2024 of file JsonUtils.cpp.
{ document_ = document; const char *begin = document_.c_str(); const char *end = begin + document_.length(); return parse( begin, end, root, collectComments ); }
bool Reader::parse | ( | std::istream & | sin, |
Value & | root, | ||
bool | collectComments = true |
||
) |
Parse from input stream.
Definition at line 2035 of file JsonUtils.cpp.
{ //std::istream_iterator<char> begin(sin); //std::istream_iterator<char> end; // Those would allow streamed input from a file, if parse() were a // template function. // Since std::string is reference-counted, this at least does not // create an extra copy. std::string doc; std::getline(sin, doc, (char)EOF); return parse( doc, root, collectComments ); }
bool Reader::readArray | ( | Token & | token | ) | [private] |
Definition at line 2417 of file JsonUtils.cpp.
{ currentValue() = Value( arrayValue ); skipSpaces(); if ( *current_ == ']' ) // empty array { Token endArray; readToken( endArray ); return true; } int index = 0; while ( true ) { Value &value = currentValue()[ index++ ]; nodes_.push( &value ); bool ok = readValue(); nodes_.pop(); if ( !ok ) // error already set return recoverFromError( tokenArrayEnd ); Token token; if ( !readToken( token ) || ( token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd ) ) { return addErrorAndRecover( "Missing ',' or ']' in array declaration", token, tokenArrayEnd ); } if ( token.type_ == tokenArrayEnd ) break; } return true; }
bool Reader::readComment | ( | ) | [private] |
Definition at line 2256 of file JsonUtils.cpp.
{ Location commentBegin = current_ - 1; Char c = getNextChar(); bool successful = false; if ( c == '*' ) successful = readCStyleComment(); else if ( c == '/' ) successful = readCppStyleComment(); if ( !successful ) return false; if ( collectComments_ ) { CommentPlacement placement = commentBefore; if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) { if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) placement = commentAfterOnSameLine; } addComment( commentBegin, current_, placement ); } return true; }
bool Reader::readCppStyleComment | ( | ) | [private] |
Definition at line 2317 of file JsonUtils.cpp.
{ while ( current_ != end_ ) { Char c = getNextChar(); if ( c == '\r' || c == '\n' ) break; } return true; }
bool Reader::readCStyleComment | ( | ) | [private] |
Definition at line 2304 of file JsonUtils.cpp.
{ while ( current_ != end_ ) { Char c = getNextChar(); if ( c == '*' && *current_ == '/' ) break; } return getNextChar() == '/'; }
void Reader::readNumber | ( | ) | [private] |
bool Reader::readObject | ( | Token & | token | ) | [private] |
Definition at line 2358 of file JsonUtils.cpp.
{ Token tokenName; std::string name; currentValue() = Value( objectValue ); while ( readToken( tokenName ) ) { bool initialTokenOk = true; while ( tokenName.type_ == tokenComment && initialTokenOk ) initialTokenOk = readToken( tokenName ); if ( !initialTokenOk ) break; if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object return true; if ( tokenName.type_ != tokenString ) break; name = ""; if ( !decodeString( tokenName, name ) ) return recoverFromError( tokenObjectEnd ); Token colon; if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) { return addErrorAndRecover( "Missing ':' after object member name", colon, tokenObjectEnd ); } Value &value = currentValue()[ name ]; nodes_.push( &value ); bool ok = readValue(); nodes_.pop(); if ( !ok ) // error already set return recoverFromError( tokenObjectEnd ); Token comma; if ( !readToken( comma ) || ( comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && comma.type_ != tokenComment ) ) { return addErrorAndRecover( "Missing ',' or '}' in object declaration", comma, tokenObjectEnd ); } bool finalizeTokenOk = true; while ( comma.type_ == tokenComment && finalizeTokenOk ) finalizeTokenOk = readToken( comma ); if ( comma.type_ == tokenObjectEnd ) return true; } return addErrorAndRecover( "Missing '}' or object member name", tokenName, tokenObjectEnd ); }
bool Reader::readString | ( | ) | [private] |
Definition at line 2342 of file JsonUtils.cpp.
{ Char c = 0; while ( current_ != end_ ) { c = getNextChar(); if ( c == '\\' ) getNextChar(); else if ( c == '"' ) break; } return c == '"'; }
bool Reader::readToken | ( | Token & | token | ) | [private] |
Definition at line 2152 of file JsonUtils.cpp.
{ skipSpaces(); token.start_ = current_; Char c = getNextChar(); bool ok = true; switch ( c ) { case '{': token.type_ = tokenObjectBegin; break; case '}': token.type_ = tokenObjectEnd; break; case '[': token.type_ = tokenArrayBegin; break; case ']': token.type_ = tokenArrayEnd; break; case '"': token.type_ = tokenString; ok = readString(); break; case '/': token.type_ = tokenComment; ok = readComment(); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': token.type_ = tokenNumber; readNumber(); break; case 't': token.type_ = tokenTrue; ok = match( "rue", 3 ); break; case 'f': token.type_ = tokenFalse; ok = match( "alse", 4 ); break; case 'n': token.type_ = tokenNull; ok = match( "ull", 3 ); break; case ',': token.type_ = tokenArraySeparator; break; case ':': token.type_ = tokenMemberSeparator; break; case 0: token.type_ = tokenEndOfStream; break; default: ok = false; break; } if ( !ok ) token.type_ = tokenError; token.end_ = current_; return true; }
bool Reader::readValue | ( | ) | [private] |
Definition at line 2080 of file JsonUtils.cpp.
{ Token token; skipCommentTokens( token ); bool successful = true; if ( collectComments_ && !commentsBefore_.empty() ) { currentValue().setComment( commentsBefore_, commentBefore ); commentsBefore_ = ""; } switch ( token.type_ ) { case tokenObjectBegin: successful = readObject( token ); break; case tokenArrayBegin: successful = readArray( token ); break; case tokenNumber: successful = decodeNumber( token ); break; case tokenString: successful = decodeString( token ); break; case tokenTrue: currentValue() = true; break; case tokenFalse: currentValue() = false; break; case tokenNull: currentValue() = Value(); break; default: return addError( "Syntax error: value, object or array expected.", token ); } if ( collectComments_ ) { lastValueEnd_ = current_; lastValue_ = ¤tValue(); } return successful; }
bool Reader::recoverFromError | ( | TokenType | skipUntilToken | ) | [private] |
Definition at line 2618 of file JsonUtils.cpp.
{ int errorCount = int(errors_.size()); Token skip; while ( true ) { if ( !readToken(skip) ) errors_.resize( errorCount ); // discard errors caused by recovery if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) break; } errors_.resize( errorCount ); return false; }
void Reader::skipCommentTokens | ( | Token & | token | ) | [private] |
Definition at line 2131 of file JsonUtils.cpp.
{ do { readToken( token ); } while ( token.type_ == tokenComment ); }
void Reader::skipSpaces | ( | ) | [private] |
void osgEarth::Json::Reader::skipUntilSpace | ( | ) | [private] |
Location osgEarth::Json::Reader::begin_ [private] |
bool osgEarth::Json::Reader::collectComments_ [private] |
std::string osgEarth::Json::Reader::commentsBefore_ [private] |
Location osgEarth::Json::Reader::current_ [private] |
std::string osgEarth::Json::Reader::document_ [private] |
Location osgEarth::Json::Reader::end_ [private] |
Errors osgEarth::Json::Reader::errors_ [private] |
Value* osgEarth::Json::Reader::lastValue_ [private] |
Nodes osgEarth::Json::Reader::nodes_ [private] |