osgEarth 2.1.1
Classes | Public Types | Public Member Functions | Private Types | Private Member Functions | Private Attributes

osgEarth::Json::Reader Class Reference

Unserialize a JSON document into a Value. More...

Collaboration diagram for osgEarth::Json::Reader:

List of all members.

Classes

class  ErrorInfo
class  Token

Public Types

typedef char Char
typedef const CharLocation

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< ErrorInfoErrors
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 &current, 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 ()
ValuecurrentValue ()
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_
ValuelastValue_
std::string commentsBefore_
bool collectComments_

Detailed Description

Unserialize a JSON document into a Value.

Definition at line 1283 of file JsonUtils.


Member Typedef Documentation

Definition at line 1286 of file JsonUtils.

typedef std::deque<ErrorInfo> osgEarth::Json::Reader::Errors [private]

Definition at line 1363 of file JsonUtils.

Definition at line 1287 of file JsonUtils.

typedef std::stack<Value *> osgEarth::Json::Reader::Nodes [private]

Definition at line 1405 of file JsonUtils.


Member Enumeration Documentation

Enumerator:
tokenEndOfStream 
tokenObjectBegin 
tokenObjectEnd 
tokenArrayBegin 
tokenArrayEnd 
tokenString 
tokenNumber 
tokenTrue 
tokenFalse 
tokenNull 
tokenArraySeparator 
tokenMemberSeparator 
tokenComment 
tokenError 

Definition at line 1329 of file JsonUtils.


Constructor & Destructor Documentation

Reader::Reader ( )

Definition at line 2019 of file JsonUtils.cpp.

{
}

Member Function Documentation

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 );
   }
}

Here is the call graph for this function:

Here is the caller graph for this function:

bool Reader::addError ( const std::string &  message,
Token token,
Location  extra = 0 
) [private]

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 );
}

Here is the call graph for this function:

Here is the caller graph for this function:

Value & Reader::currentValue ( ) [private]

Definition at line 2645 of file JsonUtils.cpp.

{
   return *(nodes_.top());
}

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

bool Reader::expectToken ( TokenType  type,
Token token,
const char *  message 
) [private]

Definition at line 2142 of file JsonUtils.cpp.

{
   readToken( token );
   if ( token.type_ != type )
      return addError( message, token );
   return true;
}

Here is the call graph for this function:

std::string Reader::getFormatedErrorMessages ( ) const

Returns a user friendly string that list errors in the parsed document.

Returns:
Formatted error message with the list of errors with their location in the parsed document. An empty string is returned if no error occurred during parsing.

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

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;
}

Here is the caller graph for this function:

Reader::Char Reader::getNextChar ( ) [private]

Definition at line 2652 of file JsonUtils.cpp.

{
   if ( current_ == end_ )
      return 0;
   return *current_++;
}

Here is the caller graph for this function:

bool Reader::match ( Location  pattern,
int  patternLength 
) [private]

Definition at line 2241 of file JsonUtils.cpp.

{
   if ( end_ - current_ < patternLength )
      return false;
   int index = patternLength;
   while ( index-- )
      if ( current_[index] != pattern[index] )
         return false;
   current_ += patternLength;
   return true;
}

Here is the caller graph for this function:

bool Reader::parse ( const char *  beginDoc,
const char *  endDoc,
Value root,
bool  collectComments = true 
)

Read a Value from a JSON document.

Parameters:
documentUTF-8 encoded string containing the document to read.
root[out] Contains the root value of the document if it was successfully parsed.
collectCommentstrue to collect comment and allow writing them back during serialization, false to discard comments.
Returns:
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;
}

Here is the call graph for this function:

bool Reader::parse ( const std::string &  document,
Value root,
bool  collectComments = true 
)

Read a Value from a JSON document.

Parameters:
documentUTF-8 encoded string containing the document to read.
root[out] Contains the root value of the document if it was successfully parsed.
collectCommentstrue to collect comment and allow writing them back during serialization, false to discard comments.
Returns:
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 );
}

Here is the caller graph for this function:

bool Reader::parse ( std::istream &  sin,
Value root,
bool  collectComments = true 
)

Parse from input stream.

See also:
Json::operator>>(std::istream&, Json::Value&).

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 );
}

Here is the call graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

bool Reader::readCStyleComment ( ) [private]

Definition at line 2304 of file JsonUtils.cpp.

{
   while ( current_ != end_ )
   {
      Char c = getNextChar();
      if ( c == '*'  &&  *current_ == '/' )
         break;
   }
   return getNextChar() == '/';
}

Here is the call graph for this function:

Here is the caller graph for this function:

void Reader::readNumber ( ) [private]

Definition at line 2330 of file JsonUtils.cpp.

{
   while ( current_ != end_ )
   {
      if ( !(*current_ >= '0'  &&  *current_ <= '9')  &&
           !in( *current_, '.', 'e', 'E', '+', '-' ) )
         break;
      ++current_;
   }
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 );
}

Here is the call graph for this function:

Here is the caller graph for this function:

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 == '"';
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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_ = &currentValue();
   }

   return successful;
}

Here is the call graph for this function:

Here is the caller graph for this function:

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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void Reader::skipCommentTokens ( Token token) [private]

Definition at line 2131 of file JsonUtils.cpp.

{
   do
   {
      readToken( token );
   }
   while ( token.type_ == tokenComment );
}

Here is the call graph for this function:

Here is the caller graph for this function:

void Reader::skipSpaces ( ) [private]

Definition at line 2227 of file JsonUtils.cpp.

{
   while ( current_ != end_ )
   {
      Char c = *current_;
      if ( c == ' '  ||  c == '\t'  ||  c == '\r'  ||  c == '\n' )
         ++current_;
      else
         break;
   }
}

Here is the caller graph for this function:

void osgEarth::Json::Reader::skipUntilSpace ( ) [private]

Member Data Documentation

Definition at line 1409 of file JsonUtils.

Definition at line 1415 of file JsonUtils.

Definition at line 1414 of file JsonUtils.

Definition at line 1411 of file JsonUtils.

std::string osgEarth::Json::Reader::document_ [private]

Definition at line 1408 of file JsonUtils.

Definition at line 1410 of file JsonUtils.

Definition at line 1407 of file JsonUtils.

Definition at line 1413 of file JsonUtils.

Definition at line 1412 of file JsonUtils.

Definition at line 1406 of file JsonUtils.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines