6 #if !defined(JSON_IS_AMALGAMATION)
10 #endif // if !defined(JSON_IS_AMALGAMATION)
18 #if _MSC_VER >= 1400 // VC++ 8.0
19 #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
28 : allowComments_( true )
29 , strictRoot_( false )
57 return c == c1 || c == c2 || c == c3 || c == c4;
63 return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
71 for ( ;begin < end; ++begin )
72 if ( *begin ==
'\n' || *begin ==
'\r' )
88 : features_( features )
96 bool collectComments )
99 const char *begin = document_.c_str();
100 const char *end = begin + document_.length();
101 return parse( begin, end, root, collectComments );
108 bool collectComments )
118 std::getline(sin, doc, (
char)EOF);
119 return parse( doc, root, collectComments );
125 bool collectComments )
129 collectComments =
false;
134 collectComments_ = collectComments;
138 commentsBefore_ =
"";
140 while ( !nodes_.empty() )
142 nodes_.push( &root );
144 bool successful = readValue();
146 skipCommentTokens( token );
147 if ( collectComments_ && !commentsBefore_.empty() )
154 token.type_ = tokenError;
155 token.start_ = beginDoc;
157 addError(
"A valid JSON document must be either an array or an object value.",
170 skipCommentTokens( token );
171 bool successful =
true;
173 if ( collectComments_ && !commentsBefore_.empty() )
176 commentsBefore_ =
"";
180 switch ( token.type_ )
182 case tokenObjectBegin:
183 successful = readObject( token );
185 case tokenArrayBegin:
186 successful = readArray( token );
189 successful = decodeNumber( token );
192 successful = decodeString( token );
195 currentValue() =
true;
198 currentValue() =
false;
201 currentValue() = Value();
204 return addError(
"Syntax error: value, object or array expected.", token );
207 if ( collectComments_ )
209 lastValueEnd_ = current_;
210 lastValue_ = ¤tValue();
218 Reader::skipCommentTokens( Token &token )
226 while ( token.type_ == tokenComment );
236 Reader::expectToken( TokenType type, Token &token,
const char *message )
239 if ( token.type_ != type )
240 return addError( message, token );
246 Reader::readToken( Token &token )
249 token.start_ = current_;
250 Char c = getNextChar();
255 token.type_ = tokenObjectBegin;
258 token.type_ = tokenObjectEnd;
261 token.type_ = tokenArrayBegin;
264 token.type_ = tokenArrayEnd;
267 token.type_ = tokenString;
271 token.type_ = tokenComment;
285 token.type_ = tokenNumber;
289 token.type_ = tokenTrue;
290 ok = match(
"rue", 3 );
293 token.type_ = tokenFalse;
294 ok = match(
"alse", 4 );
297 token.type_ = tokenNull;
298 ok = match(
"ull", 3 );
301 token.type_ = tokenArraySeparator;
304 token.type_ = tokenMemberSeparator;
307 token.type_ = tokenEndOfStream;
314 token.type_ = tokenError;
315 token.end_ = current_;
323 while ( current_ != end_ )
326 if ( c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n' )
335 Reader::match( Location pattern,
338 if ( end_ - current_ < patternLength )
340 int index = patternLength;
342 if ( current_[index] != pattern[index] )
344 current_ += patternLength;
350 Reader::readComment()
352 Location commentBegin = current_ - 1;
353 Char c = getNextChar();
354 bool successful =
false;
356 successful = readCStyleComment();
358 successful = readCppStyleComment();
362 if ( collectComments_ )
365 if ( lastValueEnd_ && !
containsNewLine( lastValueEnd_, commentBegin ) )
371 addComment( commentBegin, current_, placement );
378 Reader::addComment( Location begin,
382 assert( collectComments_ );
385 assert( lastValue_ != 0 );
386 lastValue_->
setComment( std::string( begin, end ), placement );
390 if ( !commentsBefore_.empty() )
391 commentsBefore_ +=
"\n";
392 commentsBefore_ += std::string( begin, end );
398 Reader::readCStyleComment()
400 while ( current_ != end_ )
402 Char c = getNextChar();
403 if ( c ==
'*' && *current_ ==
'/' )
406 return getNextChar() ==
'/';
411 Reader::readCppStyleComment()
413 while ( current_ != end_ )
415 Char c = getNextChar();
416 if ( c ==
'\r' || c ==
'\n' )
426 while ( current_ != end_ )
428 if ( !(*current_ >=
'0' && *current_ <=
'9') &&
429 !
in( *current_,
'.',
'e',
'E',
'+',
'-' ) )
439 while ( current_ != end_ )
452 Reader::readObject( Token & )
457 while ( readToken( tokenName ) )
459 bool initialTokenOk =
true;
460 while ( tokenName.type_ == tokenComment && initialTokenOk )
461 initialTokenOk = readToken( tokenName );
462 if ( !initialTokenOk )
464 if ( tokenName.type_ == tokenObjectEnd && name.empty() )
466 if ( tokenName.type_ != tokenString )
470 if ( !decodeString( tokenName, name ) )
471 return recoverFromError( tokenObjectEnd );
474 if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
476 return addErrorAndRecover(
"Missing ':' after object member name",
480 Value &value = currentValue()[ name ];
481 nodes_.push( &value );
482 bool ok = readValue();
485 return recoverFromError( tokenObjectEnd );
488 if ( !readToken( comma )
489 || ( comma.type_ != tokenObjectEnd &&
490 comma.type_ != tokenArraySeparator &&
491 comma.type_ != tokenComment ) )
493 return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
497 bool finalizeTokenOk =
true;
498 while ( comma.type_ == tokenComment &&
500 finalizeTokenOk = readToken( comma );
501 if ( comma.type_ == tokenObjectEnd )
504 return addErrorAndRecover(
"Missing '}' or object member name",
511 Reader::readArray( Token & )
515 if ( *current_ ==
']' )
518 readToken( endArray );
524 Value &value = currentValue()[ index++ ];
525 nodes_.push( &value );
526 bool ok = readValue();
529 return recoverFromError( tokenArrayEnd );
533 ok = readToken( token );
534 while ( token.type_ == tokenComment && ok )
536 ok = readToken( token );
538 bool badTokenType = ( token.type_ != tokenArraySeparator &&
539 token.type_ != tokenArrayEnd );
540 if ( !ok || badTokenType )
542 return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
546 if ( token.type_ == tokenArrayEnd )
554 Reader::decodeNumber( Token &token )
556 bool isDouble =
false;
557 for (
Location inspect = token.start_; inspect != token.end_; ++inspect )
560 ||
in( *inspect,
'.',
'e',
'E',
'+' )
561 || ( *inspect ==
'-' && inspect != token.start_ );
564 return decodeDouble( token );
569 bool isNegative = *current ==
'-';
573 : Value::maxLargestUInt;
574 Value::LargestUInt threshold = maxIntegerValue / 10;
576 assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 );
577 Value::LargestUInt value = 0;
578 while ( current < token.end_ )
581 if ( c < '0' || c >
'9' )
582 return addError(
"'" + std::string( token.start_, token.end_ ) +
"' is not a number.", token );
584 if ( value >= threshold )
589 if ( current != token.end_ || digit > lastDigitThreshold )
591 return decodeDouble( token );
594 value = value * 10 + digit;
601 currentValue() = value;
607 Reader::decodeDouble( Token &token )
610 const int bufferSize = 32;
612 int length = int(token.end_ - token.start_);
613 if ( length <= bufferSize )
615 Char buffer[bufferSize+1];
616 memcpy( buffer, token.start_, length );
618 count = sscanf( buffer,
"%lf", &value );
622 std::string buffer( token.start_, token.end_ );
623 count = sscanf( buffer.c_str(),
"%lf", &value );
627 return addError(
"'" + std::string( token.start_, token.end_ ) +
"' is not a number.", token );
628 currentValue() = value;
634 Reader::decodeString( Token &token )
637 if ( !decodeString( token, decoded ) )
639 currentValue() = decoded;
645 Reader::decodeString( Token &token, std::string &decoded )
647 decoded.reserve( token.end_ - token.start_ - 2 );
648 Location current = token.start_ + 1;
650 while ( current != end )
655 else if ( c ==
'\\' )
657 if ( current == end )
658 return addError(
"Empty escape sequence in string", token, current );
659 Char escape = *current++;
662 case '"': decoded +=
'"';
break;
663 case '/': decoded +=
'/';
break;
664 case '\\': decoded +=
'\\';
break;
665 case 'b': decoded +=
'\b';
break;
666 case 'f': decoded +=
'\f';
break;
667 case 'n': decoded +=
'\n';
break;
668 case 'r': decoded +=
'\r';
break;
669 case 't': decoded +=
'\t';
break;
672 unsigned int unicode;
673 if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
679 return addError(
"Bad escape sequence in string", token, current );
691 Reader::decodeUnicodeCodePoint( Token &token,
694 unsigned int &unicode )
697 if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
699 if (unicode >= 0xD800 && unicode <= 0xDBFF)
702 if (end - current < 6)
703 return addError(
"additional six characters expected to parse unicode surrogate pair.", token, current );
704 unsigned int surrogatePair;
705 if (*(current++) ==
'\\' && *(current++)==
'u')
707 if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
709 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
715 return addError(
"expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
721 Reader::decodeUnicodeEscapeSequence( Token &token,
724 unsigned int &unicode )
726 if ( end - current < 4 )
727 return addError(
"Bad unicode escape sequence in string: four digits expected.", token, current );
729 for (
int index =0; index < 4; ++index )
733 if ( c >=
'0' && c <=
'9' )
735 else if ( c >=
'a' && c <=
'f' )
736 unicode += c -
'a' + 10;
737 else if ( c >=
'A' && c <=
'F' )
738 unicode += c -
'A' + 10;
740 return addError(
"Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
747 Reader::addError(
const std::string &message,
753 info.message_ = message;
755 errors_.push_back( info );
761 Reader::recoverFromError( TokenType skipUntilToken )
763 int errorCount = int(errors_.size());
767 if ( !readToken(skip) )
768 errors_.resize( errorCount );
769 if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream )
772 errors_.resize( errorCount );
778 Reader::addErrorAndRecover(
const std::string &message,
780 TokenType skipUntilToken )
782 addError( message, token );
783 return recoverFromError( skipUntilToken );
788 Reader::currentValue()
790 return *(nodes_.top());
795 Reader::getNextChar()
797 if ( current_ == end_ )
804 Reader::getLocationLineAndColumn( Location location,
811 while ( current < location && current != end_ )
816 if ( *current ==
'\n' )
818 lastLineStart = current;
821 else if ( c ==
'\n' )
823 lastLineStart = current;
828 column = int(location - lastLineStart) + 1;
834 Reader::getLocationLineAndColumn( Location location )
const
837 getLocationLineAndColumn( location, line, column );
838 char buffer[18+16+16+1];
839 sprintf( buffer,
"Line %d, Column %d", line, column );
855 std::string formattedMessage;
856 for ( Errors::const_iterator itError = errors_.begin();
857 itError != errors_.end();
860 const ErrorInfo &error = *itError;
861 formattedMessage +=
"* " + getLocationLineAndColumn( error.token_.start_ ) +
"\n";
862 formattedMessage +=
" " + error.message_ +
"\n";
864 formattedMessage +=
"See " + getLocationLineAndColumn( error.extra_ ) +
" for detail.\n";
866 return formattedMessage;
873 bool ok = reader.
parse(sin, root,
true);
static std::string codePointToUTF8(unsigned int cp)
Converts a unicode code-point to UTF-8.
array value (ordered list)
object value (collection of name/value pairs).
std::istream & operator>>(std::istream &, Value &)
Read from 'sin' into 'root'.
std::string getFormatedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
static const Int maxInt
Maximum signed int value that can be stored in a Json::Value.
Json::LargestUInt LargestUInt
Features()
Initialize the configuration like JsonConfig::allFeatures;.
void setComment(const char *comment, CommentPlacement placement)
Comments must be //... or /* ... */.
static const LargestInt minLargestInt
Minimum signed integer value that can be stored in a Json::Value.
bool allowComments_
true if comments are allowed. Default: true.
bool parse(const std::string &document, Value &root, bool collectComments=true)
Read a Value from a JSON document.
static bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4)
JSON (JavaScript Object Notation).
Json::LargestInt LargestInt
static Features all()
A configuration that allows all features and assumes all strings are UTF-8.
a comment on the line after a value (only make sense for root value)
Unserialize a JSON document into a Value.
static Features strictMode()
A configuration that is strictly compatible with the JSON specification.
bool strictRoot_
true if root must be either an array or an object value. Default: false.
static bool containsNewLine(Reader::Location begin, Reader::Location end)
Configuration passed to reader and writer.
a comment placed on the line before a value
Reader()
Constructs a Reader allowing all features for parsing.
std::string getFormattedErrorMessages() const
Returns a user friendly string that list errors in the parsed document.
a comment just after a value on the same line