Added features that allow the reader to accept common non-standard JSON.

This is a version of patch #17, from Clay Wood:

    http://sourceforge.net/p/jsoncpp/patches/17/
This commit is contained in:
Aaron Jacobs 2014-04-23 23:28:23 +00:00
parent 77cd83890d
commit 642befc836
3 changed files with 67 additions and 11 deletions

View File

@ -42,6 +42,12 @@ namespace Json {
/// \c true if root must be either an array or an object value. Default: \c false. /// \c true if root must be either an array or an object value. Default: \c false.
bool strictRoot_; bool strictRoot_;
/// \c true if dropped null placeholders are allowed. Default: \c false.
bool allowDroppedNullPlaceholders_;
/// \c true if numeric object key are allowed. Default: \c false.
bool allowNumericKeys_;
}; };
} // namespace Json } // namespace Json

View File

@ -146,9 +146,11 @@ namespace Json {
bool readObject( Token &token ); bool readObject( Token &token );
bool readArray( Token &token ); bool readArray( Token &token );
bool decodeNumber( Token &token ); bool decodeNumber( Token &token );
bool decodeNumber( Token &token, Value &decoded );
bool decodeString( Token &token ); bool decodeString( Token &token );
bool decodeString( Token &token, std::string &decoded ); bool decodeString( Token &token, std::string &decoded );
bool decodeDouble( Token &token ); bool decodeDouble( Token &token );
bool decodeDouble( Token &token, Value &decoded );
bool decodeUnicodeCodePoint( Token &token, bool decodeUnicodeCodePoint( Token &token,
Location &current, Location &current,
Location end, Location end,

View File

@ -28,6 +28,8 @@ namespace Json {
Features::Features() Features::Features()
: allowComments_( true ) : allowComments_( true )
, strictRoot_( false ) , strictRoot_( false )
, allowDroppedNullPlaceholders_ ( false )
, allowNumericKeys_ ( false )
{ {
} }
@ -45,6 +47,8 @@ Features::strictMode()
Features features; Features features;
features.allowComments_ = false; features.allowComments_ = false;
features.strictRoot_ = true; features.strictRoot_ = true;
features.allowDroppedNullPlaceholders_ = false;
features.allowNumericKeys_ = false;
return features; return features;
} }
@ -230,6 +234,16 @@ Reader::readValue()
case tokenNull: case tokenNull:
currentValue() = Value(); currentValue() = Value();
break; break;
case tokenArraySeparator:
if ( features_.allowDroppedNullPlaceholders_ )
{
// "Un-read" the current token and mark the current value as a null
// token.
current_--;
currentValue() = Value();
break;
}
// Else, fall through...
default: default:
return addError( "Syntax error: value, object or array expected.", token ); return addError( "Syntax error: value, object or array expected.", token );
} }
@ -493,12 +507,24 @@ Reader::readObject( Token &/*tokenStart*/ )
break; break;
if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object
return true; return true;
if ( tokenName.type_ != tokenString )
break;
name = ""; name = "";
if ( tokenName.type_ == tokenString )
{
if ( !decodeString( tokenName, name ) ) if ( !decodeString( tokenName, name ) )
return recoverFromError( tokenObjectEnd ); return recoverFromError( tokenObjectEnd );
}
else if ( tokenName.type_ == tokenNumber &&
features_.allowNumericKeys_ )
{
Value numberName;
if ( !decodeNumber( tokenName, numberName ) )
return recoverFromError( tokenObjectEnd );
name = numberName.asString();
}
else
{
break;
}
Token colon; Token colon;
if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
@ -582,6 +608,17 @@ Reader::readArray( Token &/*tokenStart*/ )
bool bool
Reader::decodeNumber( Token &token ) Reader::decodeNumber( Token &token )
{
Value decoded;
if ( !decodeNumber( token, decoded ) )
return false;
currentValue() = decoded;
return true;
}
bool
Reader::decodeNumber( Token &token, Value &decoded )
{ {
bool isDouble = false; bool isDouble = false;
for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
@ -591,7 +628,7 @@ Reader::decodeNumber( Token &token )
|| ( *inspect == '-' && inspect != token.start_ ); || ( *inspect == '-' && inspect != token.start_ );
} }
if ( isDouble ) if ( isDouble )
return decodeDouble( token ); return decodeDouble( token, decoded );
// Attempts to parse the number as an integer. If the number is // Attempts to parse the number as an integer. If the number is
// larger than the maximum supported value of an integer then // larger than the maximum supported value of an integer then
// we decode the number as a double. // we decode the number as a double.
@ -619,23 +656,34 @@ Reader::decodeNumber( Token &token )
current != token.end_ || current != token.end_ ||
digit > maxIntegerValue % 10) digit > maxIntegerValue % 10)
{ {
return decodeDouble( token ); return decodeDouble( token, decoded );
} }
} }
value = value * 10 + digit; value = value * 10 + digit;
} }
if ( isNegative ) if ( isNegative )
currentValue() = -Value::LargestInt( value ); decoded = -Value::LargestInt( value );
else if ( value <= Value::LargestUInt(Value::maxInt) ) else if ( value <= Value::LargestUInt(Value::maxInt) )
currentValue() = Value::LargestInt( value ); decoded = Value::LargestInt( value );
else else
currentValue() = value; decoded = value;
return true; return true;
} }
bool bool
Reader::decodeDouble( Token &token ) Reader::decodeDouble( Token &token )
{
Value decoded;
if ( !decodeDouble( token, decoded ) )
return false;
currentValue() = decoded;
return true;
}
bool
Reader::decodeDouble( Token &token, Value &decoded )
{ {
double value = 0; double value = 0;
const int bufferSize = 32; const int bufferSize = 32;
@ -669,7 +717,7 @@ Reader::decodeDouble( Token &token )
if ( count != 1 ) if ( count != 1 )
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
currentValue() = value; decoded = value;
return true; return true;
} }