6 #if !defined(JSON_IS_AMALGAMATION)
10 #endif // if !defined(JSON_IS_AMALGAMATION)
19 #if _MSC_VER >= 1400 // VC++ 8.0
20 #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
29 : allowComments_( true )
30 , strictRoot_( false )
58 return c == c1 || c == c2 || c == c3 || c == c4;
64 return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
72 for ( ;begin < end; ++begin )
73 if ( *begin ==
'\n' || *begin ==
'\r' )
89 : features_( features )
97 bool collectComments )
100 const char *begin = document_.c_str();
101 const char *end = begin + document_.length();
102 return parse( begin, end, root, collectComments );
109 bool collectComments )
119 std::getline(sin, doc, (
char)EOF);
120 return parse( doc, root, collectComments );
126 bool collectComments )
130 collectComments =
false;
135 collectComments_ = collectComments;
139 commentsBefore_ =
"";
141 while ( !nodes_.empty() )
143 nodes_.push( &root );
145 bool successful = readValue();
147 skipCommentTokens( token );
148 if ( collectComments_ && !commentsBefore_.empty() )
155 token.type_ = tokenError;
156 token.start_ = beginDoc;
158 addError(
"A valid JSON document must be either an array or an object value.",
171 skipCommentTokens( token );
172 bool successful =
true;
174 if ( collectComments_ && !commentsBefore_.empty() )
177 commentsBefore_ =
"";
181 switch ( token.type_ )
183 case tokenObjectBegin:
184 successful = readObject( token );
186 case tokenArrayBegin:
187 successful = readArray( token );
190 successful = decodeNumber( token );
193 successful = decodeString( token );
196 currentValue() =
true;
199 currentValue() =
false;
202 currentValue() = Value();
205 return addError(
"Syntax error: value, object or array expected.", token );
208 if ( collectComments_ )
210 lastValueEnd_ = current_;
211 lastValue_ = ¤tValue();
219 Reader::skipCommentTokens( Token &token )
227 while ( token.type_ == tokenComment );
237 Reader::expectToken( TokenType type, Token &token,
const char *message )
240 if ( token.type_ != type )
241 return addError( message, token );
247 Reader::readToken( Token &token )
250 token.start_ = current_;
251 Char c = getNextChar();
256 token.type_ = tokenObjectBegin;
259 token.type_ = tokenObjectEnd;
262 token.type_ = tokenArrayBegin;
265 token.type_ = tokenArrayEnd;
268 token.type_ = tokenString;
272 token.type_ = tokenComment;
286 token.type_ = tokenNumber;
290 token.type_ = tokenTrue;
291 ok = match(
"rue", 3 );
294 token.type_ = tokenFalse;
295 ok = match(
"alse", 4 );
298 token.type_ = tokenNull;
299 ok = match(
"ull", 3 );
302 token.type_ = tokenArraySeparator;
305 token.type_ = tokenMemberSeparator;
308 token.type_ = tokenEndOfStream;
315 token.type_ = tokenError;
316 token.end_ = current_;
324 while ( current_ != end_ )
327 if ( c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n' )
336 Reader::match( Location pattern,
339 if ( end_ - current_ < patternLength )
341 int index = patternLength;
343 if ( current_[index] != pattern[index] )
345 current_ += patternLength;
351 Reader::readComment()
353 Location commentBegin = current_ - 1;
354 Char c = getNextChar();
355 bool successful =
false;
357 successful = readCStyleComment();
359 successful = readCppStyleComment();
363 if ( collectComments_ )
366 if ( lastValueEnd_ && !
containsNewLine( lastValueEnd_, commentBegin ) )
372 addComment( commentBegin, current_, placement );
379 Reader::addComment( Location begin,
383 assert( collectComments_ );
386 assert( lastValue_ != 0 );
387 lastValue_->
setComment( std::string( begin, end ), placement );
391 if ( !commentsBefore_.empty() )
392 commentsBefore_ +=
"\n";
393 commentsBefore_ += std::string( begin, end );
399 Reader::readCStyleComment()
401 while ( current_ != end_ )
403 Char c = getNextChar();
404 if ( c ==
'*' && *current_ ==
'/' )
407 return getNextChar() ==
'/';
412 Reader::readCppStyleComment()
414 while ( current_ != end_ )
416 Char c = getNextChar();
417 if ( c ==
'\r' || c ==
'\n' )
427 while ( current_ != end_ )
429 if ( !(*current_ >=
'0' && *current_ <=
'9') &&
430 !
in( *current_,
'.',
'e',
'E',
'+',
'-' ) )
440 while ( current_ != end_ )
453 Reader::readObject( Token & )
458 while ( readToken( tokenName ) )
460 bool initialTokenOk =
true;
461 while ( tokenName.type_ == tokenComment && initialTokenOk )
462 initialTokenOk = readToken( tokenName );
463 if ( !initialTokenOk )
465 if ( tokenName.type_ == tokenObjectEnd && name.empty() )
467 if ( tokenName.type_ != tokenString )
471 if ( !decodeString( tokenName, name ) )
472 return recoverFromError( tokenObjectEnd );
475 if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
477 return addErrorAndRecover(
"Missing ':' after object member name",
481 Value &value = currentValue()[ name ];
482 nodes_.push( &value );
483 bool ok = readValue();
486 return recoverFromError( tokenObjectEnd );
489 if ( !readToken( comma )
490 || ( comma.type_ != tokenObjectEnd &&
491 comma.type_ != tokenArraySeparator &&
492 comma.type_ != tokenComment ) )
494 return addErrorAndRecover(
"Missing ',' or '}' in object declaration",
498 bool finalizeTokenOk =
true;
499 while ( comma.type_ == tokenComment &&
501 finalizeTokenOk = readToken( comma );
502 if ( comma.type_ == tokenObjectEnd )
505 return addErrorAndRecover(
"Missing '}' or object member name",
512 Reader::readArray( Token & )
516 if ( *current_ ==
']' )
519 readToken( endArray );
525 Value &value = currentValue()[ index++ ];
526 nodes_.push( &value );
527 bool ok = readValue();
530 return recoverFromError( tokenArrayEnd );
534 ok = readToken( token );
535 while ( token.type_ == tokenComment && ok )
537 ok = readToken( token );
539 bool badTokenType = ( token.type_ != tokenArraySeparator &&
540 token.type_ != tokenArrayEnd );
541 if ( !ok || badTokenType )
543 return addErrorAndRecover(
"Missing ',' or ']' in array declaration",
547 if ( token.type_ == tokenArrayEnd )
555 Reader::decodeNumber( Token &token )
557 bool isDouble =
false;
558 for (
Location inspect = token.start_; inspect != token.end_; ++inspect )
561 ||
in( *inspect,
'.',
'e',
'E',
'+' )
562 || ( *inspect ==
'-' && inspect != token.start_ );
565 return decodeDouble( token );
570 bool isNegative = *current ==
'-';
574 : Value::maxLargestUInt;
575 Value::LargestUInt threshold = maxIntegerValue / 10;
577 assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 );
578 Value::LargestUInt value = 0;
579 while ( current < token.end_ )
582 if ( c < '0' || c >
'9' )
583 return addError(
"'" + std::string( token.start_, token.end_ ) +
"' is not a number.", token );
585 if ( value >= threshold )
590 if ( current != token.end_ || digit > lastDigitThreshold )
592 return decodeDouble( token );
595 value = value * 10 + digit;
602 currentValue() = value;
608 Reader::decodeDouble( Token &token )
611 std::string buffer( token.start_, token.end_ );
612 std::istringstream is(buffer);
615 return addError(
"'" + std::string( token.start_, token.end_ ) +
"' is not a number.", token );
616 currentValue() = value;
622 Reader::decodeString( Token &token )
625 if ( !decodeString( token, decoded ) )
627 currentValue() = decoded;
633 Reader::decodeString( Token &token, std::string &decoded )
635 decoded.reserve( token.end_ - token.start_ - 2 );
636 Location current = token.start_ + 1;
638 while ( current != end )
643 else if ( c ==
'\\' )
645 if ( current == end )
646 return addError(
"Empty escape sequence in string", token, current );
647 Char escape = *current++;
650 case '"': decoded +=
'"';
break;
651 case '/': decoded +=
'/';
break;
652 case '\\': decoded +=
'\\';
break;
653 case 'b': decoded +=
'\b';
break;
654 case 'f': decoded +=
'\f';
break;
655 case 'n': decoded +=
'\n';
break;
656 case 'r': decoded +=
'\r';
break;
657 case 't': decoded +=
'\t';
break;
660 unsigned int unicode;
661 if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
667 return addError(
"Bad escape sequence in string", token, current );
679 Reader::decodeUnicodeCodePoint( Token &token,
682 unsigned int &unicode )
685 if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
687 if (unicode >= 0xD800 && unicode <= 0xDBFF)
690 if (end - current < 6)
691 return addError(
"additional six characters expected to parse unicode surrogate pair.", token, current );
692 unsigned int surrogatePair;
693 if (*(current++) ==
'\\' && *(current++)==
'u')
695 if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
697 unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
703 return addError(
"expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
709 Reader::decodeUnicodeEscapeSequence( Token &token,
712 unsigned int &unicode )
714 if ( end - current < 4 )
715 return addError(
"Bad unicode escape sequence in string: four digits expected.", token, current );
717 for (
int index =0; index < 4; ++index )
721 if ( c >=
'0' && c <=
'9' )
723 else if ( c >=
'a' && c <=
'f' )
724 unicode += c -
'a' + 10;
725 else if ( c >=
'A' && c <=
'F' )
726 unicode += c -
'A' + 10;
728 return addError(
"Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
735 Reader::addError(
const std::string &message,
741 info.message_ = message;
743 errors_.push_back( info );
749 Reader::recoverFromError( TokenType skipUntilToken )
751 int errorCount = int(errors_.size());
755 if ( !readToken(skip) )
756 errors_.resize( errorCount );
757 if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream )
760 errors_.resize( errorCount );
766 Reader::addErrorAndRecover(
const std::string &message,
768 TokenType skipUntilToken )
770 addError( message, token );
771 return recoverFromError( skipUntilToken );
776 Reader::currentValue()
778 return *(nodes_.top());
783 Reader::getNextChar()
785 if ( current_ == end_ )
792 Reader::getLocationLineAndColumn( Location location,
799 while ( current < location && current != end_ )
804 if ( *current ==
'\n' )
806 lastLineStart = current;
809 else if ( c ==
'\n' )
811 lastLineStart = current;
816 column = int(location - lastLineStart) + 1;
822 Reader::getLocationLineAndColumn( Location location )
const
825 getLocationLineAndColumn( location, line, column );
826 char buffer[18+16+16+1];
827 sprintf( buffer,
"Line %d, Column %d", line, column );
843 std::string formattedMessage;
844 for ( Errors::const_iterator itError = errors_.begin();
845 itError != errors_.end();
848 const ErrorInfo &error = *itError;
849 formattedMessage +=
"* " + getLocationLineAndColumn( error.token_.start_ ) +
"\n";
850 formattedMessage +=
" " + error.message_ +
"\n";
852 formattedMessage +=
"See " + getLocationLineAndColumn( error.extra_ ) +
" for detail.\n";
854 return formattedMessage;
861 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