rt300@13: /// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). rt300@13: /// It is intented to be used with #include rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // Beginning of content of file: LICENSE rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: /* rt300@13: The JsonCpp library's source code, including accompanying documentation, rt300@13: tests and demonstration applications, are licensed under the following rt300@13: conditions... rt300@13: rt300@13: The author (Baptiste Lepilleur) explicitly disclaims copyright in all rt300@13: jurisdictions which recognize such a disclaimer. In such jurisdictions, rt300@13: this software is released into the Public Domain. rt300@13: rt300@13: In jurisdictions which do not recognize Public Domain property (e.g. Germany as of rt300@13: 2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is rt300@13: released under the terms of the MIT License (see below). rt300@13: rt300@13: In jurisdictions which recognize Public Domain property, the user of this rt300@13: software may choose to accept it either as 1) Public Domain, 2) under the rt300@13: conditions of the MIT License (see below), or 3) under the terms of dual rt300@13: Public Domain/MIT License conditions described here, as they choose. rt300@13: rt300@13: The MIT License is about as close to Public Domain as a license can get, and is rt300@13: described in clear, concise terms at: rt300@13: rt300@13: http://en.wikipedia.org/wiki/MIT_License rt300@13: rt300@13: The full text of the MIT License follows: rt300@13: rt300@13: ======================================================================== rt300@13: Copyright (c) 2007-2010 Baptiste Lepilleur rt300@13: rt300@13: Permission is hereby granted, free of charge, to any person rt300@13: obtaining a copy of this software and associated documentation rt300@13: files (the "Software"), to deal in the Software without rt300@13: restriction, including without limitation the rights to use, copy, rt300@13: modify, merge, publish, distribute, sublicense, and/or sell copies rt300@13: of the Software, and to permit persons to whom the Software is rt300@13: furnished to do so, subject to the following conditions: rt300@13: rt300@13: The above copyright notice and this permission notice shall be rt300@13: included in all copies or substantial portions of the Software. rt300@13: rt300@13: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, rt300@13: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF rt300@13: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND rt300@13: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS rt300@13: BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN rt300@13: ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN rt300@13: CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE rt300@13: SOFTWARE. rt300@13: ======================================================================== rt300@13: (END LICENSE TEXT) rt300@13: rt300@13: The MIT license is compatible with both the GPL and commercial rt300@13: software, affording one all of the rights of Public Domain with the rt300@13: minor nuisance of being required to keep the above copyright notice rt300@13: and license text in the source code. Note also that by accepting the rt300@13: Public Domain "license" you can re-license your copy using whatever rt300@13: license you like. rt300@13: rt300@13: */ rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // End of content of file: LICENSE rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: rt300@13: rt300@13: #define JSON_IS_AMALGAMATION rt300@13: rt300@13: rt300@13: #include rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // Beginning of content of file: src/lib_json/json_tool.h rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: // Copyright 2007-2010 Baptiste Lepilleur rt300@13: // Distributed under MIT license, or public domain if desired and rt300@13: // recognized in your jurisdiction. rt300@13: // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE rt300@13: rt300@13: #ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED rt300@13: # define LIB_JSONCPP_JSON_TOOL_H_INCLUDED rt300@13: rt300@13: /* This header provides common string manipulation support, such as UTF-8, rt300@13: * portable conversion from/to string... rt300@13: * rt300@13: * It is an internal header that must not be exposed. rt300@13: */ rt300@13: rt300@13: namespace Json { rt300@13: rt300@13: /// Converts a unicode code-point to UTF-8. rt300@13: static inline std::string rt300@13: codePointToUTF8(unsigned int cp) rt300@13: { rt300@13: std::string result; rt300@13: rt300@13: // based on description from http://en.wikipedia.org/wiki/UTF-8 rt300@13: rt300@13: if (cp <= 0x7f) rt300@13: { rt300@13: result.resize(1); rt300@13: result[0] = static_cast(cp); rt300@13: } rt300@13: else if (cp <= 0x7FF) rt300@13: { rt300@13: result.resize(2); rt300@13: result[1] = static_cast(0x80 | (0x3f & cp)); rt300@13: result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); rt300@13: } rt300@13: else if (cp <= 0xFFFF) rt300@13: { rt300@13: result.resize(3); rt300@13: result[2] = static_cast(0x80 | (0x3f & cp)); rt300@13: result[1] = 0x80 | static_cast((0x3f & (cp >> 6))); rt300@13: result[0] = 0xE0 | static_cast((0xf & (cp >> 12))); rt300@13: } rt300@13: else if (cp <= 0x10FFFF) rt300@13: { rt300@13: result.resize(4); rt300@13: result[3] = static_cast(0x80 | (0x3f & cp)); rt300@13: result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); rt300@13: result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); rt300@13: result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); rt300@13: } rt300@13: rt300@13: return result; rt300@13: } rt300@13: rt300@13: rt300@13: /// Returns true if ch is a control character (in range [0,32[). rt300@13: static inline bool rt300@13: isControlCharacter(char ch) rt300@13: { rt300@13: return ch > 0 && ch <= 0x1F; rt300@13: } rt300@13: rt300@13: rt300@13: enum { rt300@13: /// Constant that specify the size of the buffer that must be passed to uintToString. rt300@13: uintToStringBufferSize = 3*sizeof(LargestUInt)+1 rt300@13: }; rt300@13: rt300@13: // Defines a char buffer for use with uintToString(). rt300@13: typedef char UIntToStringBuffer[uintToStringBufferSize]; rt300@13: rt300@13: rt300@13: /** Converts an unsigned integer to string. rt300@13: * @param value Unsigned interger to convert to string rt300@13: * @param current Input/Output string buffer. rt300@13: * Must have at least uintToStringBufferSize chars free. rt300@13: */ rt300@13: static inline void rt300@13: uintToString( LargestUInt value, rt300@13: char *¤t ) rt300@13: { rt300@13: *--current = 0; rt300@13: do rt300@13: { rt300@13: *--current = char(value % 10) + '0'; rt300@13: value /= 10; rt300@13: } rt300@13: while ( value != 0 ); rt300@13: } rt300@13: rt300@13: } // namespace Json { rt300@13: rt300@13: #endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // End of content of file: src/lib_json/json_tool.h rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // Beginning of content of file: src/lib_json/json_reader.cpp rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: // Copyright 2007-2010 Baptiste Lepilleur rt300@13: // Distributed under MIT license, or public domain if desired and rt300@13: // recognized in your jurisdiction. rt300@13: // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE rt300@13: rt300@13: #if !defined(JSON_IS_AMALGAMATION) rt300@13: # include rt300@13: # include rt300@13: # include "json_tool.h" rt300@13: #endif // if !defined(JSON_IS_AMALGAMATION) rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: rt300@13: #if _MSC_VER >= 1400 // VC++ 8.0 rt300@13: #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. rt300@13: #endif rt300@13: rt300@13: namespace Json { rt300@13: rt300@13: // Implementation of class Features rt300@13: // //////////////////////////////// rt300@13: rt300@13: Features::Features() rt300@13: : allowComments_( true ) rt300@13: , strictRoot_( false ) rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: Features rt300@13: Features::all() rt300@13: { rt300@13: return Features(); rt300@13: } rt300@13: rt300@13: rt300@13: Features rt300@13: Features::strictMode() rt300@13: { rt300@13: Features features; rt300@13: features.allowComments_ = false; rt300@13: features.strictRoot_ = true; rt300@13: return features; rt300@13: } rt300@13: rt300@13: // Implementation of class Reader rt300@13: // //////////////////////////////// rt300@13: rt300@13: rt300@13: static inline bool rt300@13: in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 ) rt300@13: { rt300@13: return c == c1 || c == c2 || c == c3 || c == c4; rt300@13: } rt300@13: rt300@13: static inline bool rt300@13: in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 ) rt300@13: { rt300@13: return c == c1 || c == c2 || c == c3 || c == c4 || c == c5; rt300@13: } rt300@13: rt300@13: rt300@13: static bool rt300@13: containsNewLine( Reader::Location begin, rt300@13: Reader::Location end ) rt300@13: { rt300@13: for ( ;begin < end; ++begin ) rt300@13: if ( *begin == '\n' || *begin == '\r' ) rt300@13: return true; rt300@13: return false; rt300@13: } rt300@13: rt300@13: rt300@13: // Class Reader rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: Reader::Reader() rt300@13: : features_( Features::all() ) rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: Reader::Reader( const Features &features ) rt300@13: : features_( features ) rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::parse( const std::string &document, rt300@13: Value &root, rt300@13: bool collectComments ) rt300@13: { rt300@13: document_ = document; rt300@13: const char *begin = document_.c_str(); rt300@13: const char *end = begin + document_.length(); rt300@13: return parse( begin, end, root, collectComments ); rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::parse( std::istream& sin, rt300@13: Value &root, rt300@13: bool collectComments ) rt300@13: { rt300@13: //std::istream_iterator begin(sin); rt300@13: //std::istream_iterator end; rt300@13: // Those would allow streamed input from a file, if parse() were a rt300@13: // template function. rt300@13: rt300@13: // Since std::string is reference-counted, this at least does not rt300@13: // create an extra copy. rt300@13: std::string doc; rt300@13: std::getline(sin, doc, (char)EOF); rt300@13: return parse( doc, root, collectComments ); rt300@13: } rt300@13: rt300@13: bool rt300@13: Reader::parse( const char *beginDoc, const char *endDoc, rt300@13: Value &root, rt300@13: bool collectComments ) rt300@13: { rt300@13: if ( !features_.allowComments_ ) rt300@13: { rt300@13: collectComments = false; rt300@13: } rt300@13: rt300@13: begin_ = beginDoc; rt300@13: end_ = endDoc; rt300@13: collectComments_ = collectComments; rt300@13: current_ = begin_; rt300@13: lastValueEnd_ = 0; rt300@13: lastValue_ = 0; rt300@13: commentsBefore_ = ""; rt300@13: errors_.clear(); rt300@13: while ( !nodes_.empty() ) rt300@13: nodes_.pop(); rt300@13: nodes_.push( &root ); rt300@13: rt300@13: bool successful = readValue(); rt300@13: Token token; rt300@13: skipCommentTokens( token ); rt300@13: if ( collectComments_ && !commentsBefore_.empty() ) rt300@13: root.setComment( commentsBefore_, commentAfter ); rt300@13: if ( features_.strictRoot_ ) rt300@13: { rt300@13: if ( !root.isArray() && !root.isObject() ) rt300@13: { rt300@13: // Set error location to start of doc, ideally should be first token found in doc rt300@13: token.type_ = tokenError; rt300@13: token.start_ = beginDoc; rt300@13: token.end_ = endDoc; rt300@13: addError( "A valid JSON document must be either an array or an object value.", rt300@13: token ); rt300@13: return false; rt300@13: } rt300@13: } rt300@13: return successful; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::readValue() rt300@13: { rt300@13: Token token; rt300@13: skipCommentTokens( token ); rt300@13: bool successful = true; rt300@13: rt300@13: if ( collectComments_ && !commentsBefore_.empty() ) rt300@13: { rt300@13: currentValue().setComment( commentsBefore_, commentBefore ); rt300@13: commentsBefore_ = ""; rt300@13: } rt300@13: rt300@13: rt300@13: switch ( token.type_ ) rt300@13: { rt300@13: case tokenObjectBegin: rt300@13: successful = readObject( token ); rt300@13: break; rt300@13: case tokenArrayBegin: rt300@13: successful = readArray( token ); rt300@13: break; rt300@13: case tokenNumber: rt300@13: successful = decodeNumber( token ); rt300@13: break; rt300@13: case tokenString: rt300@13: successful = decodeString( token ); rt300@13: break; rt300@13: case tokenTrue: rt300@13: currentValue() = true; rt300@13: break; rt300@13: case tokenFalse: rt300@13: currentValue() = false; rt300@13: break; rt300@13: case tokenNull: rt300@13: currentValue() = Value(); rt300@13: break; rt300@13: default: rt300@13: return addError( "Syntax error: value, object or array expected.", token ); rt300@13: } rt300@13: rt300@13: if ( collectComments_ ) rt300@13: { rt300@13: lastValueEnd_ = current_; rt300@13: lastValue_ = ¤tValue(); rt300@13: } rt300@13: rt300@13: return successful; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Reader::skipCommentTokens( Token &token ) rt300@13: { rt300@13: if ( features_.allowComments_ ) rt300@13: { rt300@13: do rt300@13: { rt300@13: readToken( token ); rt300@13: } rt300@13: while ( token.type_ == tokenComment ); rt300@13: } rt300@13: else rt300@13: { rt300@13: readToken( token ); rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::expectToken( TokenType type, Token &token, const char *message ) rt300@13: { rt300@13: readToken( token ); rt300@13: if ( token.type_ != type ) rt300@13: return addError( message, token ); rt300@13: return true; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::readToken( Token &token ) rt300@13: { rt300@13: skipSpaces(); rt300@13: token.start_ = current_; rt300@13: Char c = getNextChar(); rt300@13: bool ok = true; rt300@13: switch ( c ) rt300@13: { rt300@13: case '{': rt300@13: token.type_ = tokenObjectBegin; rt300@13: break; rt300@13: case '}': rt300@13: token.type_ = tokenObjectEnd; rt300@13: break; rt300@13: case '[': rt300@13: token.type_ = tokenArrayBegin; rt300@13: break; rt300@13: case ']': rt300@13: token.type_ = tokenArrayEnd; rt300@13: break; rt300@13: case '"': rt300@13: token.type_ = tokenString; rt300@13: ok = readString(); rt300@13: break; rt300@13: case '/': rt300@13: token.type_ = tokenComment; rt300@13: ok = readComment(); rt300@13: break; rt300@13: case '0': rt300@13: case '1': rt300@13: case '2': rt300@13: case '3': rt300@13: case '4': rt300@13: case '5': rt300@13: case '6': rt300@13: case '7': rt300@13: case '8': rt300@13: case '9': rt300@13: case '-': rt300@13: token.type_ = tokenNumber; rt300@13: readNumber(); rt300@13: break; rt300@13: case 't': rt300@13: token.type_ = tokenTrue; rt300@13: ok = match( "rue", 3 ); rt300@13: break; rt300@13: case 'f': rt300@13: token.type_ = tokenFalse; rt300@13: ok = match( "alse", 4 ); rt300@13: break; rt300@13: case 'n': rt300@13: token.type_ = tokenNull; rt300@13: ok = match( "ull", 3 ); rt300@13: break; rt300@13: case ',': rt300@13: token.type_ = tokenArraySeparator; rt300@13: break; rt300@13: case ':': rt300@13: token.type_ = tokenMemberSeparator; rt300@13: break; rt300@13: case 0: rt300@13: token.type_ = tokenEndOfStream; rt300@13: break; rt300@13: default: rt300@13: ok = false; rt300@13: break; rt300@13: } rt300@13: if ( !ok ) rt300@13: token.type_ = tokenError; rt300@13: token.end_ = current_; rt300@13: return true; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Reader::skipSpaces() rt300@13: { rt300@13: while ( current_ != end_ ) rt300@13: { rt300@13: Char c = *current_; rt300@13: if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' ) rt300@13: ++current_; rt300@13: else rt300@13: break; rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::match( Location pattern, rt300@13: int patternLength ) rt300@13: { rt300@13: if ( end_ - current_ < patternLength ) rt300@13: return false; rt300@13: int index = patternLength; rt300@13: while ( index-- ) rt300@13: if ( current_[index] != pattern[index] ) rt300@13: return false; rt300@13: current_ += patternLength; rt300@13: return true; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::readComment() rt300@13: { rt300@13: Location commentBegin = current_ - 1; rt300@13: Char c = getNextChar(); rt300@13: bool successful = false; rt300@13: if ( c == '*' ) rt300@13: successful = readCStyleComment(); rt300@13: else if ( c == '/' ) rt300@13: successful = readCppStyleComment(); rt300@13: if ( !successful ) rt300@13: return false; rt300@13: rt300@13: if ( collectComments_ ) rt300@13: { rt300@13: CommentPlacement placement = commentBefore; rt300@13: if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) ) rt300@13: { rt300@13: if ( c != '*' || !containsNewLine( commentBegin, current_ ) ) rt300@13: placement = commentAfterOnSameLine; rt300@13: } rt300@13: rt300@13: addComment( commentBegin, current_, placement ); rt300@13: } rt300@13: return true; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Reader::addComment( Location begin, rt300@13: Location end, rt300@13: CommentPlacement placement ) rt300@13: { rt300@13: assert( collectComments_ ); rt300@13: if ( placement == commentAfterOnSameLine ) rt300@13: { rt300@13: assert( lastValue_ != 0 ); rt300@13: lastValue_->setComment( std::string( begin, end ), placement ); rt300@13: } rt300@13: else rt300@13: { rt300@13: if ( !commentsBefore_.empty() ) rt300@13: commentsBefore_ += "\n"; rt300@13: commentsBefore_ += std::string( begin, end ); rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::readCStyleComment() rt300@13: { rt300@13: while ( current_ != end_ ) rt300@13: { rt300@13: Char c = getNextChar(); rt300@13: if ( c == '*' && *current_ == '/' ) rt300@13: break; rt300@13: } rt300@13: return getNextChar() == '/'; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::readCppStyleComment() rt300@13: { rt300@13: while ( current_ != end_ ) rt300@13: { rt300@13: Char c = getNextChar(); rt300@13: if ( c == '\r' || c == '\n' ) rt300@13: break; rt300@13: } rt300@13: return true; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Reader::readNumber() rt300@13: { rt300@13: while ( current_ != end_ ) rt300@13: { rt300@13: if ( !(*current_ >= '0' && *current_ <= '9') && rt300@13: !in( *current_, '.', 'e', 'E', '+', '-' ) ) rt300@13: break; rt300@13: ++current_; rt300@13: } rt300@13: } rt300@13: rt300@13: bool rt300@13: Reader::readString() rt300@13: { rt300@13: Char c = 0; rt300@13: while ( current_ != end_ ) rt300@13: { rt300@13: c = getNextChar(); rt300@13: if ( c == '\\' ) rt300@13: getNextChar(); rt300@13: else if ( c == '"' ) rt300@13: break; rt300@13: } rt300@13: return c == '"'; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::readObject( Token &/*tokenStart*/ ) rt300@13: { rt300@13: Token tokenName; rt300@13: std::string name; rt300@13: currentValue() = Value( objectValue ); rt300@13: while ( readToken( tokenName ) ) rt300@13: { rt300@13: bool initialTokenOk = true; rt300@13: while ( tokenName.type_ == tokenComment && initialTokenOk ) rt300@13: initialTokenOk = readToken( tokenName ); rt300@13: if ( !initialTokenOk ) rt300@13: break; rt300@13: if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object rt300@13: return true; rt300@13: if ( tokenName.type_ != tokenString ) rt300@13: break; rt300@13: rt300@13: name = ""; rt300@13: if ( !decodeString( tokenName, name ) ) rt300@13: return recoverFromError( tokenObjectEnd ); rt300@13: rt300@13: Token colon; rt300@13: if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator ) rt300@13: { rt300@13: return addErrorAndRecover( "Missing ':' after object member name", rt300@13: colon, rt300@13: tokenObjectEnd ); rt300@13: } rt300@13: Value &value = currentValue()[ name ]; rt300@13: nodes_.push( &value ); rt300@13: bool ok = readValue(); rt300@13: nodes_.pop(); rt300@13: if ( !ok ) // error already set rt300@13: return recoverFromError( tokenObjectEnd ); rt300@13: rt300@13: Token comma; rt300@13: if ( !readToken( comma ) rt300@13: || ( comma.type_ != tokenObjectEnd && rt300@13: comma.type_ != tokenArraySeparator && rt300@13: comma.type_ != tokenComment ) ) rt300@13: { rt300@13: return addErrorAndRecover( "Missing ',' or '}' in object declaration", rt300@13: comma, rt300@13: tokenObjectEnd ); rt300@13: } rt300@13: bool finalizeTokenOk = true; rt300@13: while ( comma.type_ == tokenComment && rt300@13: finalizeTokenOk ) rt300@13: finalizeTokenOk = readToken( comma ); rt300@13: if ( comma.type_ == tokenObjectEnd ) rt300@13: return true; rt300@13: } rt300@13: return addErrorAndRecover( "Missing '}' or object member name", rt300@13: tokenName, rt300@13: tokenObjectEnd ); rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::readArray( Token &/*tokenStart*/ ) rt300@13: { rt300@13: currentValue() = Value( arrayValue ); rt300@13: skipSpaces(); rt300@13: if ( *current_ == ']' ) // empty array rt300@13: { rt300@13: Token endArray; rt300@13: readToken( endArray ); rt300@13: return true; rt300@13: } rt300@13: int index = 0; rt300@13: for (;;) rt300@13: { rt300@13: Value &value = currentValue()[ index++ ]; rt300@13: nodes_.push( &value ); rt300@13: bool ok = readValue(); rt300@13: nodes_.pop(); rt300@13: if ( !ok ) // error already set rt300@13: return recoverFromError( tokenArrayEnd ); rt300@13: rt300@13: Token token; rt300@13: // Accept Comment after last item in the array. rt300@13: ok = readToken( token ); rt300@13: while ( token.type_ == tokenComment && ok ) rt300@13: { rt300@13: ok = readToken( token ); rt300@13: } rt300@13: bool badTokenType = ( token.type_ != tokenArraySeparator && rt300@13: token.type_ != tokenArrayEnd ); rt300@13: if ( !ok || badTokenType ) rt300@13: { rt300@13: return addErrorAndRecover( "Missing ',' or ']' in array declaration", rt300@13: token, rt300@13: tokenArrayEnd ); rt300@13: } rt300@13: if ( token.type_ == tokenArrayEnd ) rt300@13: break; rt300@13: } rt300@13: return true; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::decodeNumber( Token &token ) rt300@13: { rt300@13: bool isDouble = false; rt300@13: for ( Location inspect = token.start_; inspect != token.end_; ++inspect ) rt300@13: { rt300@13: isDouble = isDouble rt300@13: || in( *inspect, '.', 'e', 'E', '+' ) rt300@13: || ( *inspect == '-' && inspect != token.start_ ); rt300@13: } rt300@13: if ( isDouble ) rt300@13: return decodeDouble( token ); rt300@13: // Attempts to parse the number as an integer. If the number is rt300@13: // larger than the maximum supported value of an integer then rt300@13: // we decode the number as a double. rt300@13: Location current = token.start_; rt300@13: bool isNegative = *current == '-'; rt300@13: if ( isNegative ) rt300@13: ++current; rt300@13: Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt) rt300@13: : Value::maxLargestUInt; rt300@13: Value::LargestUInt threshold = maxIntegerValue / 10; rt300@13: Value::UInt lastDigitThreshold = Value::UInt( maxIntegerValue % 10 ); rt300@13: assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 ); rt300@13: Value::LargestUInt value = 0; rt300@13: while ( current < token.end_ ) rt300@13: { rt300@13: Char c = *current++; rt300@13: if ( c < '0' || c > '9' ) rt300@13: return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); rt300@13: Value::UInt digit(c - '0'); rt300@13: if ( value >= threshold ) rt300@13: { rt300@13: // If the current digit is not the last one, or if it is rt300@13: // greater than the last digit of the maximum integer value, rt300@13: // the parse the number as a double. rt300@13: if ( current != token.end_ || digit > lastDigitThreshold ) rt300@13: { rt300@13: return decodeDouble( token ); rt300@13: } rt300@13: } rt300@13: value = value * 10 + digit; rt300@13: } rt300@13: if ( isNegative ) rt300@13: currentValue() = -Value::LargestInt( value ); rt300@13: else if ( value <= Value::LargestUInt(Value::maxInt) ) rt300@13: currentValue() = Value::LargestInt( value ); rt300@13: else rt300@13: currentValue() = value; rt300@13: return true; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::decodeDouble( Token &token ) rt300@13: { rt300@13: double value = 0; rt300@13: const int bufferSize = 32; rt300@13: int count; rt300@13: int length = int(token.end_ - token.start_); rt300@13: if ( length <= bufferSize ) rt300@13: { rt300@13: Char buffer[bufferSize+1]; rt300@13: memcpy( buffer, token.start_, length ); rt300@13: buffer[length] = 0; rt300@13: count = sscanf( buffer, "%lf", &value ); rt300@13: } rt300@13: else rt300@13: { rt300@13: std::string buffer( token.start_, token.end_ ); rt300@13: count = sscanf( buffer.c_str(), "%lf", &value ); rt300@13: } rt300@13: rt300@13: if ( count != 1 ) rt300@13: return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token ); rt300@13: currentValue() = value; rt300@13: return true; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::decodeString( Token &token ) rt300@13: { rt300@13: std::string decoded; rt300@13: if ( !decodeString( token, decoded ) ) rt300@13: return false; rt300@13: currentValue() = decoded; rt300@13: return true; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::decodeString( Token &token, std::string &decoded ) rt300@13: { rt300@13: decoded.reserve( token.end_ - token.start_ - 2 ); rt300@13: Location current = token.start_ + 1; // skip '"' rt300@13: Location end = token.end_ - 1; // do not include '"' rt300@13: while ( current != end ) rt300@13: { rt300@13: Char c = *current++; rt300@13: if ( c == '"' ) rt300@13: break; rt300@13: else if ( c == '\\' ) rt300@13: { rt300@13: if ( current == end ) rt300@13: return addError( "Empty escape sequence in string", token, current ); rt300@13: Char escape = *current++; rt300@13: switch ( escape ) rt300@13: { rt300@13: case '"': decoded += '"'; break; rt300@13: case '/': decoded += '/'; break; rt300@13: case '\\': decoded += '\\'; break; rt300@13: case 'b': decoded += '\b'; break; rt300@13: case 'f': decoded += '\f'; break; rt300@13: case 'n': decoded += '\n'; break; rt300@13: case 'r': decoded += '\r'; break; rt300@13: case 't': decoded += '\t'; break; rt300@13: case 'u': rt300@13: { rt300@13: unsigned int unicode; rt300@13: if ( !decodeUnicodeCodePoint( token, current, end, unicode ) ) rt300@13: return false; rt300@13: decoded += codePointToUTF8(unicode); rt300@13: } rt300@13: break; rt300@13: default: rt300@13: return addError( "Bad escape sequence in string", token, current ); rt300@13: } rt300@13: } rt300@13: else rt300@13: { rt300@13: decoded += c; rt300@13: } rt300@13: } rt300@13: return true; rt300@13: } rt300@13: rt300@13: bool rt300@13: Reader::decodeUnicodeCodePoint( Token &token, rt300@13: Location ¤t, rt300@13: Location end, rt300@13: unsigned int &unicode ) rt300@13: { rt300@13: rt300@13: if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) ) rt300@13: return false; rt300@13: if (unicode >= 0xD800 && unicode <= 0xDBFF) rt300@13: { rt300@13: // surrogate pairs rt300@13: if (end - current < 6) rt300@13: return addError( "additional six characters expected to parse unicode surrogate pair.", token, current ); rt300@13: unsigned int surrogatePair; rt300@13: if (*(current++) == '\\' && *(current++)== 'u') rt300@13: { rt300@13: if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair )) rt300@13: { rt300@13: unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); rt300@13: } rt300@13: else rt300@13: return false; rt300@13: } rt300@13: else rt300@13: return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current ); rt300@13: } rt300@13: return true; rt300@13: } rt300@13: rt300@13: bool rt300@13: Reader::decodeUnicodeEscapeSequence( Token &token, rt300@13: Location ¤t, rt300@13: Location end, rt300@13: unsigned int &unicode ) rt300@13: { rt300@13: if ( end - current < 4 ) rt300@13: return addError( "Bad unicode escape sequence in string: four digits expected.", token, current ); rt300@13: unicode = 0; rt300@13: for ( int index =0; index < 4; ++index ) rt300@13: { rt300@13: Char c = *current++; rt300@13: unicode *= 16; rt300@13: if ( c >= '0' && c <= '9' ) rt300@13: unicode += c - '0'; rt300@13: else if ( c >= 'a' && c <= 'f' ) rt300@13: unicode += c - 'a' + 10; rt300@13: else if ( c >= 'A' && c <= 'F' ) rt300@13: unicode += c - 'A' + 10; rt300@13: else rt300@13: return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current ); rt300@13: } rt300@13: return true; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::addError( const std::string &message, rt300@13: Token &token, rt300@13: Location extra ) rt300@13: { rt300@13: ErrorInfo info; rt300@13: info.token_ = token; rt300@13: info.message_ = message; rt300@13: info.extra_ = extra; rt300@13: errors_.push_back( info ); rt300@13: return false; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::recoverFromError( TokenType skipUntilToken ) rt300@13: { rt300@13: int errorCount = int(errors_.size()); rt300@13: Token skip; rt300@13: for (;;) rt300@13: { rt300@13: if ( !readToken(skip) ) rt300@13: errors_.resize( errorCount ); // discard errors caused by recovery rt300@13: if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream ) rt300@13: break; rt300@13: } rt300@13: errors_.resize( errorCount ); rt300@13: return false; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Reader::addErrorAndRecover( const std::string &message, rt300@13: Token &token, rt300@13: TokenType skipUntilToken ) rt300@13: { rt300@13: addError( message, token ); rt300@13: return recoverFromError( skipUntilToken ); rt300@13: } rt300@13: rt300@13: rt300@13: Value & rt300@13: Reader::currentValue() rt300@13: { rt300@13: return *(nodes_.top()); rt300@13: } rt300@13: rt300@13: rt300@13: Reader::Char rt300@13: Reader::getNextChar() rt300@13: { rt300@13: if ( current_ == end_ ) rt300@13: return 0; rt300@13: return *current_++; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Reader::getLocationLineAndColumn( Location location, rt300@13: int &line, rt300@13: int &column ) const rt300@13: { rt300@13: Location current = begin_; rt300@13: Location lastLineStart = current; rt300@13: line = 0; rt300@13: while ( current < location && current != end_ ) rt300@13: { rt300@13: Char c = *current++; rt300@13: if ( c == '\r' ) rt300@13: { rt300@13: if ( *current == '\n' ) rt300@13: ++current; rt300@13: lastLineStart = current; rt300@13: ++line; rt300@13: } rt300@13: else if ( c == '\n' ) rt300@13: { rt300@13: lastLineStart = current; rt300@13: ++line; rt300@13: } rt300@13: } rt300@13: // column & line start at 1 rt300@13: column = int(location - lastLineStart) + 1; rt300@13: ++line; rt300@13: } rt300@13: rt300@13: rt300@13: std::string rt300@13: Reader::getLocationLineAndColumn( Location location ) const rt300@13: { rt300@13: int line, column; rt300@13: getLocationLineAndColumn( location, line, column ); rt300@13: char buffer[18+16+16+1]; rt300@13: sprintf( buffer, "Line %d, Column %d", line, column ); rt300@13: return buffer; rt300@13: } rt300@13: rt300@13: rt300@13: // Deprecated. Preserved for backward compatibility rt300@13: std::string rt300@13: Reader::getFormatedErrorMessages() const rt300@13: { rt300@13: return getFormattedErrorMessages(); rt300@13: } rt300@13: rt300@13: rt300@13: std::string rt300@13: Reader::getFormattedErrorMessages() const rt300@13: { rt300@13: std::string formattedMessage; rt300@13: for ( Errors::const_iterator itError = errors_.begin(); rt300@13: itError != errors_.end(); rt300@13: ++itError ) rt300@13: { rt300@13: const ErrorInfo &error = *itError; rt300@13: formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n"; rt300@13: formattedMessage += " " + error.message_ + "\n"; rt300@13: if ( error.extra_ ) rt300@13: formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n"; rt300@13: } rt300@13: return formattedMessage; rt300@13: } rt300@13: rt300@13: rt300@13: std::istream& operator>>( std::istream &sin, Value &root ) rt300@13: { rt300@13: Json::Reader reader; rt300@13: bool ok = reader.parse(sin, root, true); rt300@13: //JSON_ASSERT( ok ); rt300@13: if (!ok) throw std::runtime_error(reader.getFormattedErrorMessages()); rt300@13: return sin; rt300@13: } rt300@13: rt300@13: rt300@13: } // namespace Json rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // End of content of file: src/lib_json/json_reader.cpp rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // Beginning of content of file: src/lib_json/json_batchallocator.h rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: // Copyright 2007-2010 Baptiste Lepilleur rt300@13: // Distributed under MIT license, or public domain if desired and rt300@13: // recognized in your jurisdiction. rt300@13: // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE rt300@13: rt300@13: #ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED rt300@13: # define JSONCPP_BATCHALLOCATOR_H_INCLUDED rt300@13: rt300@13: # include rt300@13: # include rt300@13: rt300@13: # ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION rt300@13: rt300@13: namespace Json { rt300@13: rt300@13: /* Fast memory allocator. rt300@13: * rt300@13: * This memory allocator allocates memory for a batch of object (specified by rt300@13: * the page size, the number of object in each page). rt300@13: * rt300@13: * It does not allow the destruction of a single object. All the allocated objects rt300@13: * can be destroyed at once. The memory can be either released or reused for future rt300@13: * allocation. rt300@13: * rt300@13: * The in-place new operator must be used to construct the object using the pointer rt300@13: * returned by allocate. rt300@13: */ rt300@13: template rt300@13: class BatchAllocator rt300@13: { rt300@13: public: rt300@13: typedef AllocatedType Type; rt300@13: rt300@13: BatchAllocator( unsigned int objectsPerPage = 255 ) rt300@13: : freeHead_( 0 ) rt300@13: , objectsPerPage_( objectsPerPage ) rt300@13: { rt300@13: // printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() ); rt300@13: assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space. rt300@13: assert( objectsPerPage >= 16 ); rt300@13: batches_ = allocateBatch( 0 ); // allocated a dummy page rt300@13: currentBatch_ = batches_; rt300@13: } rt300@13: rt300@13: ~BatchAllocator() rt300@13: { rt300@13: for ( BatchInfo *batch = batches_; batch; ) rt300@13: { rt300@13: BatchInfo *nextBatch = batch->next_; rt300@13: free( batch ); rt300@13: batch = nextBatch; rt300@13: } rt300@13: } rt300@13: rt300@13: /// allocate space for an array of objectPerAllocation object. rt300@13: /// @warning it is the responsability of the caller to call objects constructors. rt300@13: AllocatedType *allocate() rt300@13: { rt300@13: if ( freeHead_ ) // returns node from free list. rt300@13: { rt300@13: AllocatedType *object = freeHead_; rt300@13: freeHead_ = *(AllocatedType **)object; rt300@13: return object; rt300@13: } rt300@13: if ( currentBatch_->used_ == currentBatch_->end_ ) rt300@13: { rt300@13: currentBatch_ = currentBatch_->next_; rt300@13: while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ ) rt300@13: currentBatch_ = currentBatch_->next_; rt300@13: rt300@13: if ( !currentBatch_ ) // no free batch found, allocate a new one rt300@13: { rt300@13: currentBatch_ = allocateBatch( objectsPerPage_ ); rt300@13: currentBatch_->next_ = batches_; // insert at the head of the list rt300@13: batches_ = currentBatch_; rt300@13: } rt300@13: } rt300@13: AllocatedType *allocated = currentBatch_->used_; rt300@13: currentBatch_->used_ += objectPerAllocation; rt300@13: return allocated; rt300@13: } rt300@13: rt300@13: /// Release the object. rt300@13: /// @warning it is the responsability of the caller to actually destruct the object. rt300@13: void release( AllocatedType *object ) rt300@13: { rt300@13: assert( object != 0 ); rt300@13: *(AllocatedType **)object = freeHead_; rt300@13: freeHead_ = object; rt300@13: } rt300@13: rt300@13: private: rt300@13: struct BatchInfo rt300@13: { rt300@13: BatchInfo *next_; rt300@13: AllocatedType *used_; rt300@13: AllocatedType *end_; rt300@13: AllocatedType buffer_[objectPerAllocation]; rt300@13: }; rt300@13: rt300@13: // disabled copy constructor and assignement operator. rt300@13: BatchAllocator( const BatchAllocator & ); rt300@13: void operator =( const BatchAllocator &); rt300@13: rt300@13: static BatchInfo *allocateBatch( unsigned int objectsPerPage ) rt300@13: { rt300@13: const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation rt300@13: + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage; rt300@13: BatchInfo *batch = static_cast( malloc( mallocSize ) ); rt300@13: batch->next_ = 0; rt300@13: batch->used_ = batch->buffer_; rt300@13: batch->end_ = batch->buffer_ + objectsPerPage; rt300@13: return batch; rt300@13: } rt300@13: rt300@13: BatchInfo *batches_; rt300@13: BatchInfo *currentBatch_; rt300@13: /// Head of a single linked list within the allocated space of freeed object rt300@13: AllocatedType *freeHead_; rt300@13: unsigned int objectsPerPage_; rt300@13: }; rt300@13: rt300@13: rt300@13: } // namespace Json rt300@13: rt300@13: # endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION rt300@13: rt300@13: #endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // End of content of file: src/lib_json/json_batchallocator.h rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // Beginning of content of file: src/lib_json/json_valueiterator.inl rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: // Copyright 2007-2010 Baptiste Lepilleur rt300@13: // Distributed under MIT license, or public domain if desired and rt300@13: // recognized in your jurisdiction. rt300@13: // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE rt300@13: rt300@13: // included by json_value.cpp rt300@13: rt300@13: namespace Json { rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // class ValueIteratorBase rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: ValueIteratorBase::ValueIteratorBase() rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: : current_() rt300@13: , isNull_( true ) rt300@13: { rt300@13: } rt300@13: #else rt300@13: : isArray_( true ) rt300@13: , isNull_( true ) rt300@13: { rt300@13: iterator_.array_ = ValueInternalArray::IteratorState(); rt300@13: } rt300@13: #endif rt300@13: rt300@13: rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t ) rt300@13: : current_( current ) rt300@13: , isNull_( false ) rt300@13: { rt300@13: } rt300@13: #else rt300@13: ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state ) rt300@13: : isArray_( true ) rt300@13: { rt300@13: iterator_.array_ = state; rt300@13: } rt300@13: rt300@13: rt300@13: ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state ) rt300@13: : isArray_( false ) rt300@13: { rt300@13: iterator_.map_ = state; rt300@13: } rt300@13: #endif rt300@13: rt300@13: Value & rt300@13: ValueIteratorBase::deref() const rt300@13: { rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: return current_->second; rt300@13: #else rt300@13: if ( isArray_ ) rt300@13: return ValueInternalArray::dereference( iterator_.array_ ); rt300@13: return ValueInternalMap::value( iterator_.map_ ); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: ValueIteratorBase::increment() rt300@13: { rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: ++current_; rt300@13: #else rt300@13: if ( isArray_ ) rt300@13: ValueInternalArray::increment( iterator_.array_ ); rt300@13: ValueInternalMap::increment( iterator_.map_ ); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: ValueIteratorBase::decrement() rt300@13: { rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: --current_; rt300@13: #else rt300@13: if ( isArray_ ) rt300@13: ValueInternalArray::decrement( iterator_.array_ ); rt300@13: ValueInternalMap::decrement( iterator_.map_ ); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: ValueIteratorBase::difference_type rt300@13: ValueIteratorBase::computeDistance( const SelfType &other ) const rt300@13: { rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: # ifdef JSON_USE_CPPTL_SMALLMAP rt300@13: return current_ - other.current_; rt300@13: # else rt300@13: // Iterator for null value are initialized using the default rt300@13: // constructor, which initialize current_ to the default rt300@13: // std::map::iterator. As begin() and end() are two instance rt300@13: // of the default std::map::iterator, they can not be compared. rt300@13: // To allow this, we handle this comparison specifically. rt300@13: if ( isNull_ && other.isNull_ ) rt300@13: { rt300@13: return 0; rt300@13: } rt300@13: rt300@13: rt300@13: // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL, rt300@13: // which is the one used by default). rt300@13: // Using a portable hand-made version for non random iterator instead: rt300@13: // return difference_type( std::distance( current_, other.current_ ) ); rt300@13: difference_type myDistance = 0; rt300@13: for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it ) rt300@13: { rt300@13: ++myDistance; rt300@13: } rt300@13: return myDistance; rt300@13: # endif rt300@13: #else rt300@13: if ( isArray_ ) rt300@13: return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ ); rt300@13: return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ ); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: ValueIteratorBase::isEqual( const SelfType &other ) const rt300@13: { rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: if ( isNull_ ) rt300@13: { rt300@13: return other.isNull_; rt300@13: } rt300@13: return current_ == other.current_; rt300@13: #else rt300@13: if ( isArray_ ) rt300@13: return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ ); rt300@13: return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ ); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: ValueIteratorBase::copy( const SelfType &other ) rt300@13: { rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: current_ = other.current_; rt300@13: #else rt300@13: if ( isArray_ ) rt300@13: iterator_.array_ = other.iterator_.array_; rt300@13: iterator_.map_ = other.iterator_.map_; rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: Value rt300@13: ValueIteratorBase::key() const rt300@13: { rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: const Value::CZString czstring = (*current_).first; rt300@13: if ( czstring.c_str() ) rt300@13: { rt300@13: if ( czstring.isStaticString() ) rt300@13: return Value( StaticString( czstring.c_str() ) ); rt300@13: return Value( czstring.c_str() ); rt300@13: } rt300@13: return Value( czstring.index() ); rt300@13: #else rt300@13: if ( isArray_ ) rt300@13: return Value( ValueInternalArray::indexOf( iterator_.array_ ) ); rt300@13: bool isStatic; rt300@13: const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic ); rt300@13: if ( isStatic ) rt300@13: return Value( StaticString( memberName ) ); rt300@13: return Value( memberName ); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: UInt rt300@13: ValueIteratorBase::index() const rt300@13: { rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: const Value::CZString czstring = (*current_).first; rt300@13: if ( !czstring.c_str() ) rt300@13: return czstring.index(); rt300@13: return Value::UInt( -1 ); rt300@13: #else rt300@13: if ( isArray_ ) rt300@13: return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) ); rt300@13: return Value::UInt( -1 ); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: const char * rt300@13: ValueIteratorBase::memberName() const rt300@13: { rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: const char *name = (*current_).first.c_str(); rt300@13: return name ? name : ""; rt300@13: #else rt300@13: if ( !isArray_ ) rt300@13: return ValueInternalMap::key( iterator_.map_ ); rt300@13: return ""; rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // class ValueConstIterator rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: ValueConstIterator::ValueConstIterator() rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t ) rt300@13: : ValueIteratorBase( current ) rt300@13: { rt300@13: } rt300@13: #else rt300@13: ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state ) rt300@13: : ValueIteratorBase( state ) rt300@13: { rt300@13: } rt300@13: rt300@13: ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state ) rt300@13: : ValueIteratorBase( state ) rt300@13: { rt300@13: } rt300@13: #endif rt300@13: rt300@13: ValueConstIterator & rt300@13: ValueConstIterator::operator =( const ValueIteratorBase &other ) rt300@13: { rt300@13: copy( other ); rt300@13: return *this; rt300@13: } rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // class ValueIterator rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: ValueIterator::ValueIterator() rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t ) rt300@13: : ValueIteratorBase( current ) rt300@13: { rt300@13: } rt300@13: #else rt300@13: ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state ) rt300@13: : ValueIteratorBase( state ) rt300@13: { rt300@13: } rt300@13: rt300@13: ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state ) rt300@13: : ValueIteratorBase( state ) rt300@13: { rt300@13: } rt300@13: #endif rt300@13: rt300@13: ValueIterator::ValueIterator( const ValueConstIterator &other ) rt300@13: : ValueIteratorBase( other ) rt300@13: { rt300@13: } rt300@13: rt300@13: ValueIterator::ValueIterator( const ValueIterator &other ) rt300@13: : ValueIteratorBase( other ) rt300@13: { rt300@13: } rt300@13: rt300@13: ValueIterator & rt300@13: ValueIterator::operator =( const SelfType &other ) rt300@13: { rt300@13: copy( other ); rt300@13: return *this; rt300@13: } rt300@13: rt300@13: } // namespace Json rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // End of content of file: src/lib_json/json_valueiterator.inl rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // Beginning of content of file: src/lib_json/json_value.cpp rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: // Copyright 2007-2010 Baptiste Lepilleur rt300@13: // Distributed under MIT license, or public domain if desired and rt300@13: // recognized in your jurisdiction. rt300@13: // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE rt300@13: rt300@13: #if !defined(JSON_IS_AMALGAMATION) rt300@13: # include rt300@13: # include rt300@13: # ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR rt300@13: # include "json_batchallocator.h" rt300@13: # endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR rt300@13: #endif // if !defined(JSON_IS_AMALGAMATION) rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: #ifdef JSON_USE_CPPTL rt300@13: # include rt300@13: #endif rt300@13: #include // size_t rt300@13: rt300@13: #define JSON_ASSERT_UNREACHABLE assert( false ) rt300@13: #define JSON_ASSERT( condition ) assert( condition ); // @todo <= change this into an exception throw rt300@13: #define JSON_FAIL_MESSAGE( message ) throw std::runtime_error( message ); rt300@13: #define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) JSON_FAIL_MESSAGE( message ) rt300@13: rt300@13: namespace Json { rt300@13: rt300@13: const Value Value::null; rt300@13: const Int Value::minInt = Int( ~(UInt(-1)/2) ); rt300@13: const Int Value::maxInt = Int( UInt(-1)/2 ); rt300@13: const UInt Value::maxUInt = UInt(-1); rt300@13: const Int64 Value::minInt64 = Int64( ~(UInt64(-1)/2) ); rt300@13: const Int64 Value::maxInt64 = Int64( UInt64(-1)/2 ); rt300@13: const UInt64 Value::maxUInt64 = UInt64(-1); rt300@13: const LargestInt Value::minLargestInt = LargestInt( ~(LargestUInt(-1)/2) ); rt300@13: const LargestInt Value::maxLargestInt = LargestInt( LargestUInt(-1)/2 ); rt300@13: const LargestUInt Value::maxLargestUInt = LargestUInt(-1); rt300@13: rt300@13: rt300@13: /// Unknown size marker rt300@13: static const unsigned int unknown = (unsigned)-1; rt300@13: rt300@13: rt300@13: /** Duplicates the specified string value. rt300@13: * @param value Pointer to the string to duplicate. Must be zero-terminated if rt300@13: * length is "unknown". rt300@13: * @param length Length of the value. if equals to unknown, then it will be rt300@13: * computed using strlen(value). rt300@13: * @return Pointer on the duplicate instance of string. rt300@13: */ rt300@13: static inline char * rt300@13: duplicateStringValue( const char *value, rt300@13: unsigned int length = unknown ) rt300@13: { rt300@13: if ( length == unknown ) rt300@13: length = (unsigned int)strlen(value); rt300@13: char *newString = static_cast( malloc( length + 1 ) ); rt300@13: JSON_ASSERT_MESSAGE( newString != 0, "Failed to allocate string value buffer" ); rt300@13: memcpy( newString, value, length ); rt300@13: newString[length] = 0; rt300@13: return newString; rt300@13: } rt300@13: rt300@13: rt300@13: /** Free the string duplicated by duplicateStringValue(). rt300@13: */ rt300@13: static inline void rt300@13: releaseStringValue( char *value ) rt300@13: { rt300@13: if ( value ) rt300@13: free( value ); rt300@13: } rt300@13: rt300@13: } // namespace Json rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ValueInternals... rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: #if !defined(JSON_IS_AMALGAMATION) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: # include "json_internalarray.inl" rt300@13: # include "json_internalmap.inl" rt300@13: # endif // JSON_VALUE_USE_INTERNAL_MAP rt300@13: rt300@13: # include "json_valueiterator.inl" rt300@13: #endif // if !defined(JSON_IS_AMALGAMATION) rt300@13: rt300@13: namespace Json { rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // class Value::CommentInfo rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: rt300@13: Value::CommentInfo::CommentInfo() rt300@13: : comment_( 0 ) rt300@13: { rt300@13: } rt300@13: rt300@13: Value::CommentInfo::~CommentInfo() rt300@13: { rt300@13: if ( comment_ ) rt300@13: releaseStringValue( comment_ ); rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Value::CommentInfo::setComment( const char *text ) rt300@13: { rt300@13: if ( comment_ ) rt300@13: releaseStringValue( comment_ ); rt300@13: JSON_ASSERT( text != 0 ); rt300@13: JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /"); rt300@13: // It seems that /**/ style comments are acceptable as well. rt300@13: comment_ = duplicateStringValue( text ); rt300@13: } rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // class Value::CZString rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: # ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: rt300@13: // Notes: index_ indicates if the string was allocated when rt300@13: // a string is stored. rt300@13: rt300@13: Value::CZString::CZString( ArrayIndex index ) rt300@13: : cstr_( 0 ) rt300@13: , index_( index ) rt300@13: { rt300@13: } rt300@13: rt300@13: Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate ) rt300@13: : cstr_( allocate == duplicate ? duplicateStringValue(cstr) rt300@13: : cstr ) rt300@13: , index_( allocate ) rt300@13: { rt300@13: } rt300@13: rt300@13: Value::CZString::CZString( const CZString &other ) rt300@13: : cstr_( other.index_ != noDuplication && other.cstr_ != 0 rt300@13: ? duplicateStringValue( other.cstr_ ) rt300@13: : other.cstr_ ) rt300@13: , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate) rt300@13: : other.index_ ) rt300@13: { rt300@13: } rt300@13: rt300@13: Value::CZString::~CZString() rt300@13: { rt300@13: if ( cstr_ && index_ == duplicate ) rt300@13: releaseStringValue( const_cast( cstr_ ) ); rt300@13: } rt300@13: rt300@13: void rt300@13: Value::CZString::swap( CZString &other ) rt300@13: { rt300@13: std::swap( cstr_, other.cstr_ ); rt300@13: std::swap( index_, other.index_ ); rt300@13: } rt300@13: rt300@13: Value::CZString & rt300@13: Value::CZString::operator =( const CZString &other ) rt300@13: { rt300@13: CZString temp( other ); rt300@13: swap( temp ); rt300@13: return *this; rt300@13: } rt300@13: rt300@13: bool rt300@13: Value::CZString::operator<( const CZString &other ) const rt300@13: { rt300@13: if ( cstr_ ) rt300@13: return strcmp( cstr_, other.cstr_ ) < 0; rt300@13: return index_ < other.index_; rt300@13: } rt300@13: rt300@13: bool rt300@13: Value::CZString::operator==( const CZString &other ) const rt300@13: { rt300@13: if ( cstr_ ) rt300@13: return strcmp( cstr_, other.cstr_ ) == 0; rt300@13: return index_ == other.index_; rt300@13: } rt300@13: rt300@13: rt300@13: ArrayIndex rt300@13: Value::CZString::index() const rt300@13: { rt300@13: return index_; rt300@13: } rt300@13: rt300@13: rt300@13: const char * rt300@13: Value::CZString::c_str() const rt300@13: { rt300@13: return cstr_; rt300@13: } rt300@13: rt300@13: bool rt300@13: Value::CZString::isStaticString() const rt300@13: { rt300@13: return index_ == noDuplication; rt300@13: } rt300@13: rt300@13: #endif // ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // class Value::Value rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: /*! \internal Default constructor initialization must be equivalent to: rt300@13: * memset( this, 0, sizeof(Value) ) rt300@13: * This optimization is used in ValueInternalMap fast allocator. rt300@13: */ rt300@13: Value::Value( ValueType type ) rt300@13: : type_( type ) rt300@13: , allocated_( 0 ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: switch ( type ) rt300@13: { rt300@13: case nullValue: rt300@13: break; rt300@13: case intValue: rt300@13: case uintValue: rt300@13: value_.int_ = 0; rt300@13: break; rt300@13: case realValue: rt300@13: value_.real_ = 0.0; rt300@13: break; rt300@13: case stringValue: rt300@13: value_.string_ = 0; rt300@13: break; rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: value_.map_ = new ObjectValues(); rt300@13: break; rt300@13: #else rt300@13: case arrayValue: rt300@13: value_.array_ = arrayAllocator()->newArray(); rt300@13: break; rt300@13: case objectValue: rt300@13: value_.map_ = mapAllocator()->newMap(); rt300@13: break; rt300@13: #endif rt300@13: case booleanValue: rt300@13: value_.bool_ = false; rt300@13: break; rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: #if defined(JSON_HAS_INT64) rt300@13: Value::Value( UInt value ) rt300@13: : type_( uintValue ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.uint_ = value; rt300@13: } rt300@13: rt300@13: Value::Value( Int value ) rt300@13: : type_( intValue ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.int_ = value; rt300@13: } rt300@13: rt300@13: #endif // if defined(JSON_HAS_INT64) rt300@13: rt300@13: rt300@13: Value::Value( Int64 value ) rt300@13: : type_( intValue ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.int_ = value; rt300@13: } rt300@13: rt300@13: rt300@13: Value::Value( UInt64 value ) rt300@13: : type_( uintValue ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.uint_ = value; rt300@13: } rt300@13: rt300@13: Value::Value( double value ) rt300@13: : type_( realValue ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.real_ = value; rt300@13: } rt300@13: rt300@13: Value::Value( const char *value ) rt300@13: : type_( stringValue ) rt300@13: , allocated_( true ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.string_ = duplicateStringValue( value ); rt300@13: } rt300@13: rt300@13: rt300@13: Value::Value( const char *beginValue, rt300@13: const char *endValue ) rt300@13: : type_( stringValue ) rt300@13: , allocated_( true ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.string_ = duplicateStringValue( beginValue, rt300@13: (unsigned int)(endValue - beginValue) ); rt300@13: } rt300@13: rt300@13: rt300@13: Value::Value( const std::string &value ) rt300@13: : type_( stringValue ) rt300@13: , allocated_( true ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.string_ = duplicateStringValue( value.c_str(), rt300@13: (unsigned int)value.length() ); rt300@13: rt300@13: } rt300@13: rt300@13: Value::Value( const StaticString &value ) rt300@13: : type_( stringValue ) rt300@13: , allocated_( false ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.string_ = const_cast( value.c_str() ); rt300@13: } rt300@13: rt300@13: rt300@13: # ifdef JSON_USE_CPPTL rt300@13: Value::Value( const CppTL::ConstString &value ) rt300@13: : type_( stringValue ) rt300@13: , allocated_( true ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.string_ = duplicateStringValue( value, value.length() ); rt300@13: } rt300@13: # endif rt300@13: rt300@13: Value::Value( bool value ) rt300@13: : type_( booleanValue ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: value_.bool_ = value; rt300@13: } rt300@13: rt300@13: rt300@13: Value::Value( const Value &other ) rt300@13: : type_( other.type_ ) rt300@13: , comments_( 0 ) rt300@13: # ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: , itemIsUsed_( 0 ) rt300@13: #endif rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: case intValue: rt300@13: case uintValue: rt300@13: case realValue: rt300@13: case booleanValue: rt300@13: value_ = other.value_; rt300@13: break; rt300@13: case stringValue: rt300@13: if ( other.value_.string_ ) rt300@13: { rt300@13: value_.string_ = duplicateStringValue( other.value_.string_ ); rt300@13: allocated_ = true; rt300@13: } rt300@13: else rt300@13: value_.string_ = 0; rt300@13: break; rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: value_.map_ = new ObjectValues( *other.value_.map_ ); rt300@13: break; rt300@13: #else rt300@13: case arrayValue: rt300@13: value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ ); rt300@13: break; rt300@13: case objectValue: rt300@13: value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ ); rt300@13: break; rt300@13: #endif rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: if ( other.comments_ ) rt300@13: { rt300@13: comments_ = new CommentInfo[numberOfCommentPlacement]; rt300@13: for ( int comment =0; comment < numberOfCommentPlacement; ++comment ) rt300@13: { rt300@13: const CommentInfo &otherComment = other.comments_[comment]; rt300@13: if ( otherComment.comment_ ) rt300@13: comments_[comment].setComment( otherComment.comment_ ); rt300@13: } rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: Value::~Value() rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: case intValue: rt300@13: case uintValue: rt300@13: case realValue: rt300@13: case booleanValue: rt300@13: break; rt300@13: case stringValue: rt300@13: if ( allocated_ ) rt300@13: releaseStringValue( value_.string_ ); rt300@13: break; rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: delete value_.map_; rt300@13: break; rt300@13: #else rt300@13: case arrayValue: rt300@13: arrayAllocator()->destructArray( value_.array_ ); rt300@13: break; rt300@13: case objectValue: rt300@13: mapAllocator()->destructMap( value_.map_ ); rt300@13: break; rt300@13: #endif rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: rt300@13: if ( comments_ ) rt300@13: delete[] comments_; rt300@13: } rt300@13: rt300@13: Value & rt300@13: Value::operator=( const Value &other ) rt300@13: { rt300@13: Value temp( other ); rt300@13: swap( temp ); rt300@13: return *this; rt300@13: } rt300@13: rt300@13: void rt300@13: Value::swap( Value &other ) rt300@13: { rt300@13: ValueType temp = type_; rt300@13: type_ = other.type_; rt300@13: other.type_ = temp; rt300@13: std::swap( value_, other.value_ ); rt300@13: int temp2 = allocated_; rt300@13: allocated_ = other.allocated_; rt300@13: other.allocated_ = temp2; rt300@13: } rt300@13: rt300@13: ValueType rt300@13: Value::type() const rt300@13: { rt300@13: return type_; rt300@13: } rt300@13: rt300@13: rt300@13: int rt300@13: Value::compare( const Value &other ) const rt300@13: { rt300@13: if ( *this < other ) rt300@13: return -1; rt300@13: if ( *this > other ) rt300@13: return 1; rt300@13: return 0; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::operator <( const Value &other ) const rt300@13: { rt300@13: int typeDelta = type_ - other.type_; rt300@13: if ( typeDelta ) rt300@13: return typeDelta < 0 ? true : false; rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return false; rt300@13: case intValue: rt300@13: return value_.int_ < other.value_.int_; rt300@13: case uintValue: rt300@13: return value_.uint_ < other.value_.uint_; rt300@13: case realValue: rt300@13: return value_.real_ < other.value_.real_; rt300@13: case booleanValue: rt300@13: return value_.bool_ < other.value_.bool_; rt300@13: case stringValue: rt300@13: return ( value_.string_ == 0 && other.value_.string_ ) rt300@13: || ( other.value_.string_ rt300@13: && value_.string_ rt300@13: && strcmp( value_.string_, other.value_.string_ ) < 0 ); rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: { rt300@13: int delta = int( value_.map_->size() - other.value_.map_->size() ); rt300@13: if ( delta ) rt300@13: return delta < 0; rt300@13: return (*value_.map_) < (*other.value_.map_); rt300@13: } rt300@13: #else rt300@13: case arrayValue: rt300@13: return value_.array_->compare( *(other.value_.array_) ) < 0; rt300@13: case objectValue: rt300@13: return value_.map_->compare( *(other.value_.map_) ) < 0; rt300@13: #endif rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return false; // unreachable rt300@13: } rt300@13: rt300@13: bool rt300@13: Value::operator <=( const Value &other ) const rt300@13: { rt300@13: return !(other < *this); rt300@13: } rt300@13: rt300@13: bool rt300@13: Value::operator >=( const Value &other ) const rt300@13: { rt300@13: return !(*this < other); rt300@13: } rt300@13: rt300@13: bool rt300@13: Value::operator >( const Value &other ) const rt300@13: { rt300@13: return other < *this; rt300@13: } rt300@13: rt300@13: bool rt300@13: Value::operator ==( const Value &other ) const rt300@13: { rt300@13: //if ( type_ != other.type_ ) rt300@13: // GCC 2.95.3 says: rt300@13: // attempt to take address of bit-field structure member `Json::Value::type_' rt300@13: // Beats me, but a temp solves the problem. rt300@13: int temp = other.type_; rt300@13: if ( type_ != temp ) rt300@13: return false; rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return true; rt300@13: case intValue: rt300@13: return value_.int_ == other.value_.int_; rt300@13: case uintValue: rt300@13: return value_.uint_ == other.value_.uint_; rt300@13: case realValue: rt300@13: return value_.real_ == other.value_.real_; rt300@13: case booleanValue: rt300@13: return value_.bool_ == other.value_.bool_; rt300@13: case stringValue: rt300@13: return ( value_.string_ == other.value_.string_ ) rt300@13: || ( other.value_.string_ rt300@13: && value_.string_ rt300@13: && strcmp( value_.string_, other.value_.string_ ) == 0 ); rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: return value_.map_->size() == other.value_.map_->size() rt300@13: && (*value_.map_) == (*other.value_.map_); rt300@13: #else rt300@13: case arrayValue: rt300@13: return value_.array_->compare( *(other.value_.array_) ) == 0; rt300@13: case objectValue: rt300@13: return value_.map_->compare( *(other.value_.map_) ) == 0; rt300@13: #endif rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return false; // unreachable rt300@13: } rt300@13: rt300@13: bool rt300@13: Value::operator !=( const Value &other ) const rt300@13: { rt300@13: return !( *this == other ); rt300@13: } rt300@13: rt300@13: const char * rt300@13: Value::asCString() const rt300@13: { rt300@13: JSON_ASSERT( type_ == stringValue ); rt300@13: return value_.string_; rt300@13: } rt300@13: rt300@13: rt300@13: std::string rt300@13: Value::asString() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return ""; rt300@13: case stringValue: rt300@13: return value_.string_ ? value_.string_ : ""; rt300@13: case booleanValue: rt300@13: return value_.bool_ ? "true" : "false"; rt300@13: case intValue: rt300@13: case uintValue: rt300@13: case realValue: rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: JSON_FAIL_MESSAGE( "Type is not convertible to string" ); rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return ""; // unreachable rt300@13: } rt300@13: rt300@13: # ifdef JSON_USE_CPPTL rt300@13: CppTL::ConstString rt300@13: Value::asConstString() const rt300@13: { rt300@13: return CppTL::ConstString( asString().c_str() ); rt300@13: } rt300@13: # endif rt300@13: rt300@13: rt300@13: Value::Int rt300@13: Value::asInt() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return 0; rt300@13: case intValue: rt300@13: JSON_ASSERT_MESSAGE( value_.int_ >= minInt && value_.int_ <= maxInt, "unsigned integer out of signed int range" ); rt300@13: return Int(value_.int_); rt300@13: case uintValue: rt300@13: JSON_ASSERT_MESSAGE( value_.uint_ <= UInt(maxInt), "unsigned integer out of signed int range" ); rt300@13: return Int(value_.uint_); rt300@13: case realValue: rt300@13: JSON_ASSERT_MESSAGE( value_.real_ >= minInt && value_.real_ <= maxInt, "Real out of signed integer range" ); rt300@13: return Int( value_.real_ ); rt300@13: case booleanValue: rt300@13: return value_.bool_ ? 1 : 0; rt300@13: case stringValue: rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: JSON_FAIL_MESSAGE( "Type is not convertible to int" ); rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return 0; // unreachable; rt300@13: } rt300@13: rt300@13: rt300@13: Value::UInt rt300@13: Value::asUInt() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return 0; rt300@13: case intValue: rt300@13: JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to unsigned integer" ); rt300@13: JSON_ASSERT_MESSAGE( value_.int_ <= maxUInt, "signed integer out of UInt range" ); rt300@13: return UInt(value_.int_); rt300@13: case uintValue: rt300@13: JSON_ASSERT_MESSAGE( value_.uint_ <= maxUInt, "unsigned integer out of UInt range" ); rt300@13: return UInt(value_.uint_); rt300@13: case realValue: rt300@13: JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt, "Real out of unsigned integer range" ); rt300@13: return UInt( value_.real_ ); rt300@13: case booleanValue: rt300@13: return value_.bool_ ? 1 : 0; rt300@13: case stringValue: rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: JSON_FAIL_MESSAGE( "Type is not convertible to uint" ); rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return 0; // unreachable; rt300@13: } rt300@13: rt300@13: rt300@13: # if defined(JSON_HAS_INT64) rt300@13: rt300@13: Value::Int64 rt300@13: Value::asInt64() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return 0; rt300@13: case intValue: rt300@13: return value_.int_; rt300@13: case uintValue: rt300@13: JSON_ASSERT_MESSAGE( value_.uint_ <= UInt64(maxInt64), "unsigned integer out of Int64 range" ); rt300@13: return value_.uint_; rt300@13: case realValue: rt300@13: JSON_ASSERT_MESSAGE( value_.real_ >= minInt64 && value_.real_ <= maxInt64, "Real out of Int64 range" ); rt300@13: return Int( value_.real_ ); rt300@13: case booleanValue: rt300@13: return value_.bool_ ? 1 : 0; rt300@13: case stringValue: rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: JSON_FAIL_MESSAGE( "Type is not convertible to Int64" ); rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return 0; // unreachable; rt300@13: } rt300@13: rt300@13: rt300@13: Value::UInt64 rt300@13: Value::asUInt64() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return 0; rt300@13: case intValue: rt300@13: JSON_ASSERT_MESSAGE( value_.int_ >= 0, "Negative integer can not be converted to UInt64" ); rt300@13: return value_.int_; rt300@13: case uintValue: rt300@13: return value_.uint_; rt300@13: case realValue: rt300@13: JSON_ASSERT_MESSAGE( value_.real_ >= 0 && value_.real_ <= maxUInt64, "Real out of UInt64 range" ); rt300@13: return UInt( value_.real_ ); rt300@13: case booleanValue: rt300@13: return value_.bool_ ? 1 : 0; rt300@13: case stringValue: rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: JSON_FAIL_MESSAGE( "Type is not convertible to UInt64" ); rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return 0; // unreachable; rt300@13: } rt300@13: # endif // if defined(JSON_HAS_INT64) rt300@13: rt300@13: rt300@13: LargestInt rt300@13: Value::asLargestInt() const rt300@13: { rt300@13: #if defined(JSON_NO_INT64) rt300@13: return asInt(); rt300@13: #else rt300@13: return asInt64(); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: LargestUInt rt300@13: Value::asLargestUInt() const rt300@13: { rt300@13: #if defined(JSON_NO_INT64) rt300@13: return asUInt(); rt300@13: #else rt300@13: return asUInt64(); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: double rt300@13: Value::asDouble() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return 0.0; rt300@13: case intValue: rt300@13: return static_cast( value_.int_ ); rt300@13: case uintValue: rt300@13: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) rt300@13: return static_cast( value_.uint_ ); rt300@13: #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) rt300@13: return static_cast( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); rt300@13: #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) rt300@13: case realValue: rt300@13: return value_.real_; rt300@13: case booleanValue: rt300@13: return value_.bool_ ? 1.0 : 0.0; rt300@13: case stringValue: rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: JSON_FAIL_MESSAGE( "Type is not convertible to double" ); rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return 0; // unreachable; rt300@13: } rt300@13: rt300@13: float rt300@13: Value::asFloat() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return 0.0f; rt300@13: case intValue: rt300@13: return static_cast( value_.int_ ); rt300@13: case uintValue: rt300@13: #if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) rt300@13: return static_cast( value_.uint_ ); rt300@13: #else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) rt300@13: return static_cast( Int(value_.uint_/2) ) * 2 + Int(value_.uint_ & 1); rt300@13: #endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) rt300@13: case realValue: rt300@13: return static_cast( value_.real_ ); rt300@13: case booleanValue: rt300@13: return value_.bool_ ? 1.0f : 0.0f; rt300@13: case stringValue: rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: JSON_FAIL_MESSAGE( "Type is not convertible to float" ); rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return 0.0f; // unreachable; rt300@13: } rt300@13: rt300@13: bool rt300@13: Value::asBool() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return false; rt300@13: case intValue: rt300@13: case uintValue: rt300@13: return value_.int_ != 0; rt300@13: case realValue: rt300@13: return value_.real_ != 0.0; rt300@13: case booleanValue: rt300@13: return value_.bool_; rt300@13: case stringValue: rt300@13: return value_.string_ && value_.string_[0] != 0; rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: return value_.map_->size() != 0; rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return false; // unreachable; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isConvertibleTo( ValueType other ) const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: return true; rt300@13: case intValue: rt300@13: return ( other == nullValue && value_.int_ == 0 ) rt300@13: || other == intValue rt300@13: || ( other == uintValue && value_.int_ >= 0 ) rt300@13: || other == realValue rt300@13: || other == stringValue rt300@13: || other == booleanValue; rt300@13: case uintValue: rt300@13: return ( other == nullValue && value_.uint_ == 0 ) rt300@13: || ( other == intValue && value_.uint_ <= (unsigned)maxInt ) rt300@13: || other == uintValue rt300@13: || other == realValue rt300@13: || other == stringValue rt300@13: || other == booleanValue; rt300@13: case realValue: rt300@13: return ( other == nullValue && value_.real_ == 0.0 ) rt300@13: || ( other == intValue && value_.real_ >= minInt && value_.real_ <= maxInt ) rt300@13: || ( other == uintValue && value_.real_ >= 0 && value_.real_ <= maxUInt ) rt300@13: || other == realValue rt300@13: || other == stringValue rt300@13: || other == booleanValue; rt300@13: case booleanValue: rt300@13: return ( other == nullValue && value_.bool_ == false ) rt300@13: || other == intValue rt300@13: || other == uintValue rt300@13: || other == realValue rt300@13: || other == stringValue rt300@13: || other == booleanValue; rt300@13: case stringValue: rt300@13: return other == stringValue rt300@13: || ( other == nullValue && (!value_.string_ || value_.string_[0] == 0) ); rt300@13: case arrayValue: rt300@13: return other == arrayValue rt300@13: || ( other == nullValue && value_.map_->size() == 0 ); rt300@13: case objectValue: rt300@13: return other == objectValue rt300@13: || ( other == nullValue && value_.map_->size() == 0 ); rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return false; // unreachable; rt300@13: } rt300@13: rt300@13: rt300@13: /// Number of values in array or object rt300@13: ArrayIndex rt300@13: Value::size() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: case nullValue: rt300@13: case intValue: rt300@13: case uintValue: rt300@13: case realValue: rt300@13: case booleanValue: rt300@13: case stringValue: rt300@13: return 0; rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: // size of the array is highest index + 1 rt300@13: if ( !value_.map_->empty() ) rt300@13: { rt300@13: ObjectValues::const_iterator itLast = value_.map_->end(); rt300@13: --itLast; rt300@13: return (*itLast).first.index()+1; rt300@13: } rt300@13: return 0; rt300@13: case objectValue: rt300@13: return ArrayIndex( value_.map_->size() ); rt300@13: #else rt300@13: case arrayValue: rt300@13: return Int( value_.array_->size() ); rt300@13: case objectValue: rt300@13: return Int( value_.map_->size() ); rt300@13: #endif rt300@13: default: rt300@13: JSON_ASSERT_UNREACHABLE; rt300@13: } rt300@13: return 0; // unreachable; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::empty() const rt300@13: { rt300@13: if ( isNull() || isArray() || isObject() ) rt300@13: return size() == 0u; rt300@13: else rt300@13: return false; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::operator!() const rt300@13: { rt300@13: return isNull(); rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Value::clear() rt300@13: { rt300@13: JSON_ASSERT( type_ == nullValue || type_ == arrayValue || type_ == objectValue ); rt300@13: rt300@13: switch ( type_ ) rt300@13: { rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: value_.map_->clear(); rt300@13: break; rt300@13: #else rt300@13: case arrayValue: rt300@13: value_.array_->clear(); rt300@13: break; rt300@13: case objectValue: rt300@13: value_.map_->clear(); rt300@13: break; rt300@13: #endif rt300@13: default: rt300@13: break; rt300@13: } rt300@13: } rt300@13: rt300@13: void rt300@13: Value::resize( ArrayIndex newSize ) rt300@13: { rt300@13: JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); rt300@13: if ( type_ == nullValue ) rt300@13: *this = Value( arrayValue ); rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: ArrayIndex oldSize = size(); rt300@13: if ( newSize == 0 ) rt300@13: clear(); rt300@13: else if ( newSize > oldSize ) rt300@13: (*this)[ newSize - 1 ]; rt300@13: else rt300@13: { rt300@13: for ( ArrayIndex index = newSize; index < oldSize; ++index ) rt300@13: { rt300@13: value_.map_->erase( index ); rt300@13: } rt300@13: assert( size() == newSize ); rt300@13: } rt300@13: #else rt300@13: value_.array_->resize( newSize ); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: Value & rt300@13: Value::operator[]( ArrayIndex index ) rt300@13: { rt300@13: JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); rt300@13: if ( type_ == nullValue ) rt300@13: *this = Value( arrayValue ); rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: CZString key( index ); rt300@13: ObjectValues::iterator it = value_.map_->lower_bound( key ); rt300@13: if ( it != value_.map_->end() && (*it).first == key ) rt300@13: return (*it).second; rt300@13: rt300@13: ObjectValues::value_type defaultValue( key, null ); rt300@13: it = value_.map_->insert( it, defaultValue ); rt300@13: return (*it).second; rt300@13: #else rt300@13: return value_.array_->resolveReference( index ); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: Value & rt300@13: Value::operator[]( int index ) rt300@13: { rt300@13: JSON_ASSERT( index >= 0 ); rt300@13: return (*this)[ ArrayIndex(index) ]; rt300@13: } rt300@13: rt300@13: rt300@13: const Value & rt300@13: Value::operator[]( ArrayIndex index ) const rt300@13: { rt300@13: JSON_ASSERT( type_ == nullValue || type_ == arrayValue ); rt300@13: if ( type_ == nullValue ) rt300@13: return null; rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: CZString key( index ); rt300@13: ObjectValues::const_iterator it = value_.map_->find( key ); rt300@13: if ( it == value_.map_->end() ) rt300@13: return null; rt300@13: return (*it).second; rt300@13: #else rt300@13: Value *value = value_.array_->find( index ); rt300@13: return value ? *value : null; rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: const Value & rt300@13: Value::operator[]( int index ) const rt300@13: { rt300@13: JSON_ASSERT( index >= 0 ); rt300@13: return (*this)[ ArrayIndex(index) ]; rt300@13: } rt300@13: rt300@13: rt300@13: Value & rt300@13: Value::operator[]( const char *key ) rt300@13: { rt300@13: return resolveReference( key, false ); rt300@13: } rt300@13: rt300@13: rt300@13: Value & rt300@13: Value::resolveReference( const char *key, rt300@13: bool isStatic ) rt300@13: { rt300@13: JSON_ASSERT( type_ == nullValue || type_ == objectValue ); rt300@13: if ( type_ == nullValue ) rt300@13: *this = Value( objectValue ); rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: CZString actualKey( key, isStatic ? CZString::noDuplication rt300@13: : CZString::duplicateOnCopy ); rt300@13: ObjectValues::iterator it = value_.map_->lower_bound( actualKey ); rt300@13: if ( it != value_.map_->end() && (*it).first == actualKey ) rt300@13: return (*it).second; rt300@13: rt300@13: ObjectValues::value_type defaultValue( actualKey, null ); rt300@13: it = value_.map_->insert( it, defaultValue ); rt300@13: Value &value = (*it).second; rt300@13: return value; rt300@13: #else rt300@13: return value_.map_->resolveReference( key, isStatic ); rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: Value rt300@13: Value::get( ArrayIndex index, rt300@13: const Value &defaultValue ) const rt300@13: { rt300@13: const Value *value = &((*this)[index]); rt300@13: return value == &null ? defaultValue : *value; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isValidIndex( ArrayIndex index ) const rt300@13: { rt300@13: return index < size(); rt300@13: } rt300@13: rt300@13: rt300@13: rt300@13: const Value & rt300@13: Value::operator[]( const char *key ) const rt300@13: { rt300@13: JSON_ASSERT( type_ == nullValue || type_ == objectValue ); rt300@13: if ( type_ == nullValue ) rt300@13: return null; rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: CZString actualKey( key, CZString::noDuplication ); rt300@13: ObjectValues::const_iterator it = value_.map_->find( actualKey ); rt300@13: if ( it == value_.map_->end() ) rt300@13: return null; rt300@13: return (*it).second; rt300@13: #else rt300@13: const Value *value = value_.map_->find( key ); rt300@13: return value ? *value : null; rt300@13: #endif rt300@13: } rt300@13: rt300@13: rt300@13: Value & rt300@13: Value::operator[]( const std::string &key ) rt300@13: { rt300@13: return (*this)[ key.c_str() ]; rt300@13: } rt300@13: rt300@13: rt300@13: const Value & rt300@13: Value::operator[]( const std::string &key ) const rt300@13: { rt300@13: return (*this)[ key.c_str() ]; rt300@13: } rt300@13: rt300@13: Value & rt300@13: Value::operator[]( const StaticString &key ) rt300@13: { rt300@13: return resolveReference( key, true ); rt300@13: } rt300@13: rt300@13: rt300@13: # ifdef JSON_USE_CPPTL rt300@13: Value & rt300@13: Value::operator[]( const CppTL::ConstString &key ) rt300@13: { rt300@13: return (*this)[ key.c_str() ]; rt300@13: } rt300@13: rt300@13: rt300@13: const Value & rt300@13: Value::operator[]( const CppTL::ConstString &key ) const rt300@13: { rt300@13: return (*this)[ key.c_str() ]; rt300@13: } rt300@13: # endif rt300@13: rt300@13: rt300@13: Value & rt300@13: Value::append( const Value &value ) rt300@13: { rt300@13: return (*this)[size()] = value; rt300@13: } rt300@13: rt300@13: rt300@13: Value rt300@13: Value::get( const char *key, rt300@13: const Value &defaultValue ) const rt300@13: { rt300@13: const Value *value = &((*this)[key]); rt300@13: return value == &null ? defaultValue : *value; rt300@13: } rt300@13: rt300@13: rt300@13: Value rt300@13: Value::get( const std::string &key, rt300@13: const Value &defaultValue ) const rt300@13: { rt300@13: return get( key.c_str(), defaultValue ); rt300@13: } rt300@13: rt300@13: Value rt300@13: Value::removeMember( const char* key ) rt300@13: { rt300@13: JSON_ASSERT( type_ == nullValue || type_ == objectValue ); rt300@13: if ( type_ == nullValue ) rt300@13: return null; rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: CZString actualKey( key, CZString::noDuplication ); rt300@13: ObjectValues::iterator it = value_.map_->find( actualKey ); rt300@13: if ( it == value_.map_->end() ) rt300@13: return null; rt300@13: Value old(it->second); rt300@13: value_.map_->erase(it); rt300@13: return old; rt300@13: #else rt300@13: Value *value = value_.map_->find( key ); rt300@13: if (value){ rt300@13: Value old(*value); rt300@13: value_.map_.remove( key ); rt300@13: return old; rt300@13: } else { rt300@13: return null; rt300@13: } rt300@13: #endif rt300@13: } rt300@13: rt300@13: Value rt300@13: Value::removeMember( const std::string &key ) rt300@13: { rt300@13: return removeMember( key.c_str() ); rt300@13: } rt300@13: rt300@13: # ifdef JSON_USE_CPPTL rt300@13: Value rt300@13: Value::get( const CppTL::ConstString &key, rt300@13: const Value &defaultValue ) const rt300@13: { rt300@13: return get( key.c_str(), defaultValue ); rt300@13: } rt300@13: # endif rt300@13: rt300@13: bool rt300@13: Value::isMember( const char *key ) const rt300@13: { rt300@13: const Value *value = &((*this)[key]); rt300@13: return value != &null; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isMember( const std::string &key ) const rt300@13: { rt300@13: return isMember( key.c_str() ); rt300@13: } rt300@13: rt300@13: rt300@13: # ifdef JSON_USE_CPPTL rt300@13: bool rt300@13: Value::isMember( const CppTL::ConstString &key ) const rt300@13: { rt300@13: return isMember( key.c_str() ); rt300@13: } rt300@13: #endif rt300@13: rt300@13: Value::Members rt300@13: Value::getMemberNames() const rt300@13: { rt300@13: JSON_ASSERT( type_ == nullValue || type_ == objectValue ); rt300@13: if ( type_ == nullValue ) rt300@13: return Value::Members(); rt300@13: Members members; rt300@13: members.reserve( value_.map_->size() ); rt300@13: #ifndef JSON_VALUE_USE_INTERNAL_MAP rt300@13: ObjectValues::const_iterator it = value_.map_->begin(); rt300@13: ObjectValues::const_iterator itEnd = value_.map_->end(); rt300@13: for ( ; it != itEnd; ++it ) rt300@13: members.push_back( std::string( (*it).first.c_str() ) ); rt300@13: #else rt300@13: ValueInternalMap::IteratorState it; rt300@13: ValueInternalMap::IteratorState itEnd; rt300@13: value_.map_->makeBeginIterator( it ); rt300@13: value_.map_->makeEndIterator( itEnd ); rt300@13: for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) ) rt300@13: members.push_back( std::string( ValueInternalMap::key( it ) ) ); rt300@13: #endif rt300@13: return members; rt300@13: } rt300@13: // rt300@13: //# ifdef JSON_USE_CPPTL rt300@13: //EnumMemberNames rt300@13: //Value::enumMemberNames() const rt300@13: //{ rt300@13: // if ( type_ == objectValue ) rt300@13: // { rt300@13: // return CppTL::Enum::any( CppTL::Enum::transform( rt300@13: // CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), rt300@13: // MemberNamesTransform() ) ); rt300@13: // } rt300@13: // return EnumMemberNames(); rt300@13: //} rt300@13: // rt300@13: // rt300@13: //EnumValues rt300@13: //Value::enumValues() const rt300@13: //{ rt300@13: // if ( type_ == objectValue || type_ == arrayValue ) rt300@13: // return CppTL::Enum::anyValues( *(value_.map_), rt300@13: // CppTL::Type() ); rt300@13: // return EnumValues(); rt300@13: //} rt300@13: // rt300@13: //# endif rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isNull() const rt300@13: { rt300@13: return type_ == nullValue; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isBool() const rt300@13: { rt300@13: return type_ == booleanValue; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isInt() const rt300@13: { rt300@13: return type_ == intValue; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isUInt() const rt300@13: { rt300@13: return type_ == uintValue; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isIntegral() const rt300@13: { rt300@13: return type_ == intValue rt300@13: || type_ == uintValue rt300@13: || type_ == booleanValue; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isDouble() const rt300@13: { rt300@13: return type_ == realValue; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isNumeric() const rt300@13: { rt300@13: return isIntegral() || isDouble(); rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isString() const rt300@13: { rt300@13: return type_ == stringValue; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isArray() const rt300@13: { rt300@13: return type_ == nullValue || type_ == arrayValue; rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::isObject() const rt300@13: { rt300@13: return type_ == nullValue || type_ == objectValue; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Value::setComment( const char *comment, rt300@13: CommentPlacement placement ) rt300@13: { rt300@13: if ( !comments_ ) rt300@13: comments_ = new CommentInfo[numberOfCommentPlacement]; rt300@13: comments_[placement].setComment( comment ); rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Value::setComment( const std::string &comment, rt300@13: CommentPlacement placement ) rt300@13: { rt300@13: setComment( comment.c_str(), placement ); rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: Value::hasComment( CommentPlacement placement ) const rt300@13: { rt300@13: return comments_ != 0 && comments_[placement].comment_ != 0; rt300@13: } rt300@13: rt300@13: std::string rt300@13: Value::getComment( CommentPlacement placement ) const rt300@13: { rt300@13: if ( hasComment(placement) ) rt300@13: return comments_[placement].comment_; rt300@13: return ""; rt300@13: } rt300@13: rt300@13: rt300@13: std::string rt300@13: Value::toStyledString() const rt300@13: { rt300@13: StyledWriter writer; rt300@13: return writer.write( *this ); rt300@13: } rt300@13: rt300@13: rt300@13: Value::const_iterator rt300@13: Value::begin() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: #ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: rt300@13: if ( value_.array_ ) rt300@13: { rt300@13: ValueInternalArray::IteratorState it; rt300@13: value_.array_->makeBeginIterator( it ); rt300@13: return const_iterator( it ); rt300@13: } rt300@13: break; rt300@13: case objectValue: rt300@13: if ( value_.map_ ) rt300@13: { rt300@13: ValueInternalMap::IteratorState it; rt300@13: value_.map_->makeBeginIterator( it ); rt300@13: return const_iterator( it ); rt300@13: } rt300@13: break; rt300@13: #else rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: if ( value_.map_ ) rt300@13: return const_iterator( value_.map_->begin() ); rt300@13: break; rt300@13: #endif rt300@13: default: rt300@13: break; rt300@13: } rt300@13: return const_iterator(); rt300@13: } rt300@13: rt300@13: Value::const_iterator rt300@13: Value::end() const rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: #ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: rt300@13: if ( value_.array_ ) rt300@13: { rt300@13: ValueInternalArray::IteratorState it; rt300@13: value_.array_->makeEndIterator( it ); rt300@13: return const_iterator( it ); rt300@13: } rt300@13: break; rt300@13: case objectValue: rt300@13: if ( value_.map_ ) rt300@13: { rt300@13: ValueInternalMap::IteratorState it; rt300@13: value_.map_->makeEndIterator( it ); rt300@13: return const_iterator( it ); rt300@13: } rt300@13: break; rt300@13: #else rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: if ( value_.map_ ) rt300@13: return const_iterator( value_.map_->end() ); rt300@13: break; rt300@13: #endif rt300@13: default: rt300@13: break; rt300@13: } rt300@13: return const_iterator(); rt300@13: } rt300@13: rt300@13: rt300@13: Value::iterator rt300@13: Value::begin() rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: #ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: rt300@13: if ( value_.array_ ) rt300@13: { rt300@13: ValueInternalArray::IteratorState it; rt300@13: value_.array_->makeBeginIterator( it ); rt300@13: return iterator( it ); rt300@13: } rt300@13: break; rt300@13: case objectValue: rt300@13: if ( value_.map_ ) rt300@13: { rt300@13: ValueInternalMap::IteratorState it; rt300@13: value_.map_->makeBeginIterator( it ); rt300@13: return iterator( it ); rt300@13: } rt300@13: break; rt300@13: #else rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: if ( value_.map_ ) rt300@13: return iterator( value_.map_->begin() ); rt300@13: break; rt300@13: #endif rt300@13: default: rt300@13: break; rt300@13: } rt300@13: return iterator(); rt300@13: } rt300@13: rt300@13: Value::iterator rt300@13: Value::end() rt300@13: { rt300@13: switch ( type_ ) rt300@13: { rt300@13: #ifdef JSON_VALUE_USE_INTERNAL_MAP rt300@13: case arrayValue: rt300@13: if ( value_.array_ ) rt300@13: { rt300@13: ValueInternalArray::IteratorState it; rt300@13: value_.array_->makeEndIterator( it ); rt300@13: return iterator( it ); rt300@13: } rt300@13: break; rt300@13: case objectValue: rt300@13: if ( value_.map_ ) rt300@13: { rt300@13: ValueInternalMap::IteratorState it; rt300@13: value_.map_->makeEndIterator( it ); rt300@13: return iterator( it ); rt300@13: } rt300@13: break; rt300@13: #else rt300@13: case arrayValue: rt300@13: case objectValue: rt300@13: if ( value_.map_ ) rt300@13: return iterator( value_.map_->end() ); rt300@13: break; rt300@13: #endif rt300@13: default: rt300@13: break; rt300@13: } rt300@13: return iterator(); rt300@13: } rt300@13: rt300@13: rt300@13: // class PathArgument rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: PathArgument::PathArgument() rt300@13: : kind_( kindNone ) rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: PathArgument::PathArgument( ArrayIndex index ) rt300@13: : index_( index ) rt300@13: , kind_( kindIndex ) rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: PathArgument::PathArgument( const char *key ) rt300@13: : key_( key ) rt300@13: , kind_( kindKey ) rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: PathArgument::PathArgument( const std::string &key ) rt300@13: : key_( key.c_str() ) rt300@13: , kind_( kindKey ) rt300@13: { rt300@13: } rt300@13: rt300@13: // class Path rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: Path::Path( const std::string &path, rt300@13: const PathArgument &a1, rt300@13: const PathArgument &a2, rt300@13: const PathArgument &a3, rt300@13: const PathArgument &a4, rt300@13: const PathArgument &a5 ) rt300@13: { rt300@13: InArgs in; rt300@13: in.push_back( &a1 ); rt300@13: in.push_back( &a2 ); rt300@13: in.push_back( &a3 ); rt300@13: in.push_back( &a4 ); rt300@13: in.push_back( &a5 ); rt300@13: makePath( path, in ); rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Path::makePath( const std::string &path, rt300@13: const InArgs &in ) rt300@13: { rt300@13: const char *current = path.c_str(); rt300@13: const char *end = current + path.length(); rt300@13: InArgs::const_iterator itInArg = in.begin(); rt300@13: while ( current != end ) rt300@13: { rt300@13: if ( *current == '[' ) rt300@13: { rt300@13: ++current; rt300@13: if ( *current == '%' ) rt300@13: addPathInArg( path, in, itInArg, PathArgument::kindIndex ); rt300@13: else rt300@13: { rt300@13: ArrayIndex index = 0; rt300@13: for ( ; current != end && *current >= '0' && *current <= '9'; ++current ) rt300@13: index = index * 10 + ArrayIndex(*current - '0'); rt300@13: args_.push_back( index ); rt300@13: } rt300@13: if ( current == end || *current++ != ']' ) rt300@13: invalidPath( path, int(current - path.c_str()) ); rt300@13: } rt300@13: else if ( *current == '%' ) rt300@13: { rt300@13: addPathInArg( path, in, itInArg, PathArgument::kindKey ); rt300@13: ++current; rt300@13: } rt300@13: else if ( *current == '.' ) rt300@13: { rt300@13: ++current; rt300@13: } rt300@13: else rt300@13: { rt300@13: const char *beginName = current; rt300@13: while ( current != end && !strchr( "[.", *current ) ) rt300@13: ++current; rt300@13: args_.push_back( std::string( beginName, current ) ); rt300@13: } rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Path::addPathInArg( const std::string &path, rt300@13: const InArgs &in, rt300@13: InArgs::const_iterator &itInArg, rt300@13: PathArgument::Kind kind ) rt300@13: { rt300@13: if ( itInArg == in.end() ) rt300@13: { rt300@13: // Error: missing argument %d rt300@13: } rt300@13: else if ( (*itInArg)->kind_ != kind ) rt300@13: { rt300@13: // Error: bad argument type rt300@13: } rt300@13: else rt300@13: { rt300@13: args_.push_back( **itInArg ); rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: Path::invalidPath( const std::string &path, rt300@13: int location ) rt300@13: { rt300@13: // Error: invalid path. rt300@13: } rt300@13: rt300@13: rt300@13: const Value & rt300@13: Path::resolve( const Value &root ) const rt300@13: { rt300@13: const Value *node = &root; rt300@13: for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) rt300@13: { rt300@13: const PathArgument &arg = *it; rt300@13: if ( arg.kind_ == PathArgument::kindIndex ) rt300@13: { rt300@13: if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) rt300@13: { rt300@13: // Error: unable to resolve path (array value expected at position... rt300@13: } rt300@13: node = &((*node)[arg.index_]); rt300@13: } rt300@13: else if ( arg.kind_ == PathArgument::kindKey ) rt300@13: { rt300@13: if ( !node->isObject() ) rt300@13: { rt300@13: // Error: unable to resolve path (object value expected at position...) rt300@13: } rt300@13: node = &((*node)[arg.key_]); rt300@13: if ( node == &Value::null ) rt300@13: { rt300@13: // Error: unable to resolve path (object has no member named '' at position...) rt300@13: } rt300@13: } rt300@13: } rt300@13: return *node; rt300@13: } rt300@13: rt300@13: rt300@13: Value rt300@13: Path::resolve( const Value &root, rt300@13: const Value &defaultValue ) const rt300@13: { rt300@13: const Value *node = &root; rt300@13: for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) rt300@13: { rt300@13: const PathArgument &arg = *it; rt300@13: if ( arg.kind_ == PathArgument::kindIndex ) rt300@13: { rt300@13: if ( !node->isArray() || node->isValidIndex( arg.index_ ) ) rt300@13: return defaultValue; rt300@13: node = &((*node)[arg.index_]); rt300@13: } rt300@13: else if ( arg.kind_ == PathArgument::kindKey ) rt300@13: { rt300@13: if ( !node->isObject() ) rt300@13: return defaultValue; rt300@13: node = &((*node)[arg.key_]); rt300@13: if ( node == &Value::null ) rt300@13: return defaultValue; rt300@13: } rt300@13: } rt300@13: return *node; rt300@13: } rt300@13: rt300@13: rt300@13: Value & rt300@13: Path::make( Value &root ) const rt300@13: { rt300@13: Value *node = &root; rt300@13: for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it ) rt300@13: { rt300@13: const PathArgument &arg = *it; rt300@13: if ( arg.kind_ == PathArgument::kindIndex ) rt300@13: { rt300@13: if ( !node->isArray() ) rt300@13: { rt300@13: // Error: node is not an array at position ... rt300@13: } rt300@13: node = &((*node)[arg.index_]); rt300@13: } rt300@13: else if ( arg.kind_ == PathArgument::kindKey ) rt300@13: { rt300@13: if ( !node->isObject() ) rt300@13: { rt300@13: // Error: node is not an object at position... rt300@13: } rt300@13: node = &((*node)[arg.key_]); rt300@13: } rt300@13: } rt300@13: return *node; rt300@13: } rt300@13: rt300@13: rt300@13: } // namespace Json rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // End of content of file: src/lib_json/json_value.cpp rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // Beginning of content of file: src/lib_json/json_writer.cpp rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: // Copyright 2007-2010 Baptiste Lepilleur rt300@13: // Distributed under MIT license, or public domain if desired and rt300@13: // recognized in your jurisdiction. rt300@13: // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE rt300@13: rt300@13: #if !defined(JSON_IS_AMALGAMATION) rt300@13: # include rt300@13: # include "json_tool.h" rt300@13: #endif // if !defined(JSON_IS_AMALGAMATION) rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: #include rt300@13: rt300@13: #if _MSC_VER >= 1400 // VC++ 8.0 rt300@13: #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated. rt300@13: #endif rt300@13: rt300@13: namespace Json { rt300@13: rt300@13: static bool containsControlCharacter( const char* str ) rt300@13: { rt300@13: while ( *str ) rt300@13: { rt300@13: if ( isControlCharacter( *(str++) ) ) rt300@13: return true; rt300@13: } rt300@13: return false; rt300@13: } rt300@13: rt300@13: rt300@13: std::string valueToString( LargestInt value ) rt300@13: { rt300@13: UIntToStringBuffer buffer; rt300@13: char *current = buffer + sizeof(buffer); rt300@13: bool isNegative = value < 0; rt300@13: if ( isNegative ) rt300@13: value = -value; rt300@13: uintToString( LargestUInt(value), current ); rt300@13: if ( isNegative ) rt300@13: *--current = '-'; rt300@13: assert( current >= buffer ); rt300@13: return current; rt300@13: } rt300@13: rt300@13: rt300@13: std::string valueToString( LargestUInt value ) rt300@13: { rt300@13: UIntToStringBuffer buffer; rt300@13: char *current = buffer + sizeof(buffer); rt300@13: uintToString( value, current ); rt300@13: assert( current >= buffer ); rt300@13: return current; rt300@13: } rt300@13: rt300@13: #if defined(JSON_HAS_INT64) rt300@13: rt300@13: std::string valueToString( Int value ) rt300@13: { rt300@13: return valueToString( LargestInt(value) ); rt300@13: } rt300@13: rt300@13: rt300@13: std::string valueToString( UInt value ) rt300@13: { rt300@13: return valueToString( LargestUInt(value) ); rt300@13: } rt300@13: rt300@13: #endif // # if defined(JSON_HAS_INT64) rt300@13: rt300@13: rt300@13: std::string valueToString( double value ) rt300@13: { rt300@13: char buffer[32]; rt300@13: #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. rt300@13: sprintf_s(buffer, sizeof(buffer), "%#.16g", value); rt300@13: #else rt300@13: sprintf(buffer, "%#.16g", value); rt300@13: #endif rt300@13: char* ch = buffer + strlen(buffer) - 1; rt300@13: if (*ch != '0') return buffer; // nothing to truncate, so save time rt300@13: while(ch > buffer && *ch == '0'){ rt300@13: --ch; rt300@13: } rt300@13: char* last_nonzero = ch; rt300@13: while(ch >= buffer){ rt300@13: switch(*ch){ rt300@13: case '0': rt300@13: case '1': rt300@13: case '2': rt300@13: case '3': rt300@13: case '4': rt300@13: case '5': rt300@13: case '6': rt300@13: case '7': rt300@13: case '8': rt300@13: case '9': rt300@13: --ch; rt300@13: continue; rt300@13: case '.': rt300@13: // Truncate zeroes to save bytes in output, but keep one. rt300@13: *(last_nonzero+2) = '\0'; rt300@13: return buffer; rt300@13: default: rt300@13: return buffer; rt300@13: } rt300@13: } rt300@13: return buffer; rt300@13: } rt300@13: rt300@13: rt300@13: std::string valueToString( bool value ) rt300@13: { rt300@13: return value ? "true" : "false"; rt300@13: } rt300@13: rt300@13: std::string valueToQuotedString( const char *value ) rt300@13: { rt300@13: // Not sure how to handle unicode... rt300@13: if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value )) rt300@13: return std::string("\"") + value + "\""; rt300@13: // We have to walk value and escape any special characters. rt300@13: // Appending to std::string is not efficient, but this should be rare. rt300@13: // (Note: forward slashes are *not* rare, but I am not escaping them.) rt300@13: std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL rt300@13: std::string result; rt300@13: result.reserve(maxsize); // to avoid lots of mallocs rt300@13: result += "\""; rt300@13: for (const char* c=value; *c != 0; ++c) rt300@13: { rt300@13: switch(*c) rt300@13: { rt300@13: case '\"': rt300@13: result += "\\\""; rt300@13: break; rt300@13: case '\\': rt300@13: result += "\\\\"; rt300@13: break; rt300@13: case '\b': rt300@13: result += "\\b"; rt300@13: break; rt300@13: case '\f': rt300@13: result += "\\f"; rt300@13: break; rt300@13: case '\n': rt300@13: result += "\\n"; rt300@13: break; rt300@13: case '\r': rt300@13: result += "\\r"; rt300@13: break; rt300@13: case '\t': rt300@13: result += "\\t"; rt300@13: break; rt300@13: //case '/': rt300@13: // Even though \/ is considered a legal escape in JSON, a bare rt300@13: // slash is also legal, so I see no reason to escape it. rt300@13: // (I hope I am not misunderstanding something. rt300@13: // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); rt300@13: result += oss.str(); rt300@13: } rt300@13: else rt300@13: { rt300@13: result += *c; rt300@13: } rt300@13: break; rt300@13: } rt300@13: } rt300@13: result += "\""; rt300@13: return result; rt300@13: } rt300@13: rt300@13: // Class Writer rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: Writer::~Writer() rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: // Class FastWriter rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: FastWriter::FastWriter() rt300@13: : yamlCompatiblityEnabled_( false ) rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: FastWriter::enableYAMLCompatibility() rt300@13: { rt300@13: yamlCompatiblityEnabled_ = true; rt300@13: } rt300@13: rt300@13: rt300@13: std::string rt300@13: FastWriter::write( const Value &root ) rt300@13: { rt300@13: document_ = ""; rt300@13: writeValue( root ); rt300@13: document_ += "\n"; rt300@13: return document_; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: FastWriter::writeValue( const Value &value ) rt300@13: { rt300@13: switch ( value.type() ) rt300@13: { rt300@13: case nullValue: rt300@13: document_ += "null"; rt300@13: break; rt300@13: case intValue: rt300@13: document_ += valueToString( value.asLargestInt() ); rt300@13: break; rt300@13: case uintValue: rt300@13: document_ += valueToString( value.asLargestUInt() ); rt300@13: break; rt300@13: case realValue: rt300@13: document_ += valueToString( value.asDouble() ); rt300@13: break; rt300@13: case stringValue: rt300@13: document_ += valueToQuotedString( value.asCString() ); rt300@13: break; rt300@13: case booleanValue: rt300@13: document_ += valueToString( value.asBool() ); rt300@13: break; rt300@13: case arrayValue: rt300@13: { rt300@13: document_ += "["; rt300@13: int size = value.size(); rt300@13: for ( int index =0; index < size; ++index ) rt300@13: { rt300@13: if ( index > 0 ) rt300@13: document_ += ","; rt300@13: writeValue( value[index] ); rt300@13: } rt300@13: document_ += "]"; rt300@13: } rt300@13: break; rt300@13: case objectValue: rt300@13: { rt300@13: Value::Members members( value.getMemberNames() ); rt300@13: document_ += "{"; rt300@13: for ( Value::Members::iterator it = members.begin(); rt300@13: it != members.end(); rt300@13: ++it ) rt300@13: { rt300@13: const std::string &name = *it; rt300@13: if ( it != members.begin() ) rt300@13: document_ += ","; rt300@13: document_ += valueToQuotedString( name.c_str() ); rt300@13: document_ += yamlCompatiblityEnabled_ ? ": " rt300@13: : ":"; rt300@13: writeValue( value[name] ); rt300@13: } rt300@13: document_ += "}"; rt300@13: } rt300@13: break; rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: // Class StyledWriter rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: StyledWriter::StyledWriter() rt300@13: : rightMargin_( 74 ) rt300@13: , indentSize_( 3 ) rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: std::string rt300@13: StyledWriter::write( const Value &root ) rt300@13: { rt300@13: document_ = ""; rt300@13: addChildValues_ = false; rt300@13: indentString_ = ""; rt300@13: writeCommentBeforeValue( root ); rt300@13: writeValue( root ); rt300@13: writeCommentAfterValueOnSameLine( root ); rt300@13: document_ += "\n"; rt300@13: return document_; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledWriter::writeValue( const Value &value ) rt300@13: { rt300@13: switch ( value.type() ) rt300@13: { rt300@13: case nullValue: rt300@13: pushValue( "null" ); rt300@13: break; rt300@13: case intValue: rt300@13: pushValue( valueToString( value.asLargestInt() ) ); rt300@13: break; rt300@13: case uintValue: rt300@13: pushValue( valueToString( value.asLargestUInt() ) ); rt300@13: break; rt300@13: case realValue: rt300@13: pushValue( valueToString( value.asDouble() ) ); rt300@13: break; rt300@13: case stringValue: rt300@13: pushValue( valueToQuotedString( value.asCString() ) ); rt300@13: break; rt300@13: case booleanValue: rt300@13: pushValue( valueToString( value.asBool() ) ); rt300@13: break; rt300@13: case arrayValue: rt300@13: writeArrayValue( value); rt300@13: break; rt300@13: case objectValue: rt300@13: { rt300@13: Value::Members members( value.getMemberNames() ); rt300@13: if ( members.empty() ) rt300@13: pushValue( "{}" ); rt300@13: else rt300@13: { rt300@13: writeWithIndent( "{" ); rt300@13: indent(); rt300@13: Value::Members::iterator it = members.begin(); rt300@13: for (;;) rt300@13: { rt300@13: const std::string &name = *it; rt300@13: const Value &childValue = value[name]; rt300@13: writeCommentBeforeValue( childValue ); rt300@13: writeWithIndent( valueToQuotedString( name.c_str() ) ); rt300@13: document_ += " : "; rt300@13: writeValue( childValue ); rt300@13: if ( ++it == members.end() ) rt300@13: { rt300@13: writeCommentAfterValueOnSameLine( childValue ); rt300@13: break; rt300@13: } rt300@13: document_ += ","; rt300@13: writeCommentAfterValueOnSameLine( childValue ); rt300@13: } rt300@13: unindent(); rt300@13: writeWithIndent( "}" ); rt300@13: } rt300@13: } rt300@13: break; rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledWriter::writeArrayValue( const Value &value ) rt300@13: { rt300@13: unsigned size = value.size(); rt300@13: if ( size == 0 ) rt300@13: pushValue( "[]" ); rt300@13: else rt300@13: { rt300@13: bool isArrayMultiLine = isMultineArray( value ); rt300@13: if ( isArrayMultiLine ) rt300@13: { rt300@13: writeWithIndent( "[" ); rt300@13: indent(); rt300@13: bool hasChildValue = !childValues_.empty(); rt300@13: unsigned index =0; rt300@13: for (;;) rt300@13: { rt300@13: const Value &childValue = value[index]; rt300@13: writeCommentBeforeValue( childValue ); rt300@13: if ( hasChildValue ) rt300@13: writeWithIndent( childValues_[index] ); rt300@13: else rt300@13: { rt300@13: writeIndent(); rt300@13: writeValue( childValue ); rt300@13: } rt300@13: if ( ++index == size ) rt300@13: { rt300@13: writeCommentAfterValueOnSameLine( childValue ); rt300@13: break; rt300@13: } rt300@13: document_ += ","; rt300@13: writeCommentAfterValueOnSameLine( childValue ); rt300@13: } rt300@13: unindent(); rt300@13: writeWithIndent( "]" ); rt300@13: } rt300@13: else // output on a single line rt300@13: { rt300@13: assert( childValues_.size() == size ); rt300@13: document_ += "[ "; rt300@13: for ( unsigned index =0; index < size; ++index ) rt300@13: { rt300@13: if ( index > 0 ) rt300@13: document_ += ", "; rt300@13: document_ += childValues_[index]; rt300@13: } rt300@13: document_ += " ]"; rt300@13: } rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: StyledWriter::isMultineArray( const Value &value ) rt300@13: { rt300@13: int size = value.size(); rt300@13: bool isMultiLine = size*3 >= rightMargin_ ; rt300@13: childValues_.clear(); rt300@13: for ( int index =0; index < size && !isMultiLine; ++index ) rt300@13: { rt300@13: const Value &childValue = value[index]; rt300@13: isMultiLine = isMultiLine || rt300@13: ( (childValue.isArray() || childValue.isObject()) && rt300@13: childValue.size() > 0 ); rt300@13: } rt300@13: if ( !isMultiLine ) // check if line length > max line length rt300@13: { rt300@13: childValues_.reserve( size ); rt300@13: addChildValues_ = true; rt300@13: int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' rt300@13: for ( int index =0; index < size && !isMultiLine; ++index ) rt300@13: { rt300@13: writeValue( value[index] ); rt300@13: lineLength += int( childValues_[index].length() ); rt300@13: isMultiLine = isMultiLine && hasCommentForValue( value[index] ); rt300@13: } rt300@13: addChildValues_ = false; rt300@13: isMultiLine = isMultiLine || lineLength >= rightMargin_; rt300@13: } rt300@13: return isMultiLine; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledWriter::pushValue( const std::string &value ) rt300@13: { rt300@13: if ( addChildValues_ ) rt300@13: childValues_.push_back( value ); rt300@13: else rt300@13: document_ += value; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledWriter::writeIndent() rt300@13: { rt300@13: if ( !document_.empty() ) rt300@13: { rt300@13: char last = document_[document_.length()-1]; rt300@13: if ( last == ' ' ) // already indented rt300@13: return; rt300@13: if ( last != '\n' ) // Comments may add new-line rt300@13: document_ += '\n'; rt300@13: } rt300@13: document_ += indentString_; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledWriter::writeWithIndent( const std::string &value ) rt300@13: { rt300@13: writeIndent(); rt300@13: document_ += value; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledWriter::indent() rt300@13: { rt300@13: indentString_ += std::string( indentSize_, ' ' ); rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledWriter::unindent() rt300@13: { rt300@13: assert( int(indentString_.size()) >= indentSize_ ); rt300@13: indentString_.resize( indentString_.size() - indentSize_ ); rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledWriter::writeCommentBeforeValue( const Value &root ) rt300@13: { rt300@13: if ( !root.hasComment( commentBefore ) ) rt300@13: return; rt300@13: document_ += normalizeEOL( root.getComment( commentBefore ) ); rt300@13: document_ += "\n"; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledWriter::writeCommentAfterValueOnSameLine( const Value &root ) rt300@13: { rt300@13: if ( root.hasComment( commentAfterOnSameLine ) ) rt300@13: document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); rt300@13: rt300@13: if ( root.hasComment( commentAfter ) ) rt300@13: { rt300@13: document_ += "\n"; rt300@13: document_ += normalizeEOL( root.getComment( commentAfter ) ); rt300@13: document_ += "\n"; rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: StyledWriter::hasCommentForValue( const Value &value ) rt300@13: { rt300@13: return value.hasComment( commentBefore ) rt300@13: || value.hasComment( commentAfterOnSameLine ) rt300@13: || value.hasComment( commentAfter ); rt300@13: } rt300@13: rt300@13: rt300@13: std::string rt300@13: StyledWriter::normalizeEOL( const std::string &text ) rt300@13: { rt300@13: std::string normalized; rt300@13: normalized.reserve( text.length() ); rt300@13: const char *begin = text.c_str(); rt300@13: const char *end = begin + text.length(); rt300@13: const char *current = begin; rt300@13: while ( current != end ) rt300@13: { rt300@13: char c = *current++; rt300@13: if ( c == '\r' ) // mac or dos EOL rt300@13: { rt300@13: if ( *current == '\n' ) // convert dos EOL rt300@13: ++current; rt300@13: normalized += '\n'; rt300@13: } rt300@13: else // handle unix EOL & other char rt300@13: normalized += c; rt300@13: } rt300@13: return normalized; rt300@13: } rt300@13: rt300@13: rt300@13: // Class StyledStreamWriter rt300@13: // ////////////////////////////////////////////////////////////////// rt300@13: rt300@13: StyledStreamWriter::StyledStreamWriter( std::string indentation ) rt300@13: : document_(NULL) rt300@13: , rightMargin_( 74 ) rt300@13: , indentation_( indentation ) rt300@13: { rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledStreamWriter::write( std::ostream &out, const Value &root ) rt300@13: { rt300@13: document_ = &out; rt300@13: addChildValues_ = false; rt300@13: indentString_ = ""; rt300@13: writeCommentBeforeValue( root ); rt300@13: writeValue( root ); rt300@13: writeCommentAfterValueOnSameLine( root ); rt300@13: *document_ << "\n"; rt300@13: document_ = NULL; // Forget the stream, for safety. rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledStreamWriter::writeValue( const Value &value ) rt300@13: { rt300@13: switch ( value.type() ) rt300@13: { rt300@13: case nullValue: rt300@13: pushValue( "null" ); rt300@13: break; rt300@13: case intValue: rt300@13: pushValue( valueToString( value.asLargestInt() ) ); rt300@13: break; rt300@13: case uintValue: rt300@13: pushValue( valueToString( value.asLargestUInt() ) ); rt300@13: break; rt300@13: case realValue: rt300@13: pushValue( valueToString( value.asDouble() ) ); rt300@13: break; rt300@13: case stringValue: rt300@13: pushValue( valueToQuotedString( value.asCString() ) ); rt300@13: break; rt300@13: case booleanValue: rt300@13: pushValue( valueToString( value.asBool() ) ); rt300@13: break; rt300@13: case arrayValue: rt300@13: writeArrayValue( value); rt300@13: break; rt300@13: case objectValue: rt300@13: { rt300@13: Value::Members members( value.getMemberNames() ); rt300@13: if ( members.empty() ) rt300@13: pushValue( "{}" ); rt300@13: else rt300@13: { rt300@13: writeWithIndent( "{" ); rt300@13: indent(); rt300@13: Value::Members::iterator it = members.begin(); rt300@13: for (;;) rt300@13: { rt300@13: const std::string &name = *it; rt300@13: const Value &childValue = value[name]; rt300@13: writeCommentBeforeValue( childValue ); rt300@13: writeWithIndent( valueToQuotedString( name.c_str() ) ); rt300@13: *document_ << " : "; rt300@13: writeValue( childValue ); rt300@13: if ( ++it == members.end() ) rt300@13: { rt300@13: writeCommentAfterValueOnSameLine( childValue ); rt300@13: break; rt300@13: } rt300@13: *document_ << ","; rt300@13: writeCommentAfterValueOnSameLine( childValue ); rt300@13: } rt300@13: unindent(); rt300@13: writeWithIndent( "}" ); rt300@13: } rt300@13: } rt300@13: break; rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledStreamWriter::writeArrayValue( const Value &value ) rt300@13: { rt300@13: unsigned size = value.size(); rt300@13: if ( size == 0 ) rt300@13: pushValue( "[]" ); rt300@13: else rt300@13: { rt300@13: bool isArrayMultiLine = isMultineArray( value ); rt300@13: if ( isArrayMultiLine ) rt300@13: { rt300@13: writeWithIndent( "[" ); rt300@13: indent(); rt300@13: bool hasChildValue = !childValues_.empty(); rt300@13: unsigned index =0; rt300@13: for (;;) rt300@13: { rt300@13: const Value &childValue = value[index]; rt300@13: writeCommentBeforeValue( childValue ); rt300@13: if ( hasChildValue ) rt300@13: writeWithIndent( childValues_[index] ); rt300@13: else rt300@13: { rt300@13: writeIndent(); rt300@13: writeValue( childValue ); rt300@13: } rt300@13: if ( ++index == size ) rt300@13: { rt300@13: writeCommentAfterValueOnSameLine( childValue ); rt300@13: break; rt300@13: } rt300@13: *document_ << ","; rt300@13: writeCommentAfterValueOnSameLine( childValue ); rt300@13: } rt300@13: unindent(); rt300@13: writeWithIndent( "]" ); rt300@13: } rt300@13: else // output on a single line rt300@13: { rt300@13: assert( childValues_.size() == size ); rt300@13: *document_ << "[ "; rt300@13: for ( unsigned index =0; index < size; ++index ) rt300@13: { rt300@13: if ( index > 0 ) rt300@13: *document_ << ", "; rt300@13: *document_ << childValues_[index]; rt300@13: } rt300@13: *document_ << " ]"; rt300@13: } rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: StyledStreamWriter::isMultineArray( const Value &value ) rt300@13: { rt300@13: int size = value.size(); rt300@13: bool isMultiLine = size*3 >= rightMargin_ ; rt300@13: childValues_.clear(); rt300@13: for ( int index =0; index < size && !isMultiLine; ++index ) rt300@13: { rt300@13: const Value &childValue = value[index]; rt300@13: isMultiLine = isMultiLine || rt300@13: ( (childValue.isArray() || childValue.isObject()) && rt300@13: childValue.size() > 0 ); rt300@13: } rt300@13: if ( !isMultiLine ) // check if line length > max line length rt300@13: { rt300@13: childValues_.reserve( size ); rt300@13: addChildValues_ = true; rt300@13: int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]' rt300@13: for ( int index =0; index < size && !isMultiLine; ++index ) rt300@13: { rt300@13: writeValue( value[index] ); rt300@13: lineLength += int( childValues_[index].length() ); rt300@13: isMultiLine = isMultiLine && hasCommentForValue( value[index] ); rt300@13: } rt300@13: addChildValues_ = false; rt300@13: isMultiLine = isMultiLine || lineLength >= rightMargin_; rt300@13: } rt300@13: return isMultiLine; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledStreamWriter::pushValue( const std::string &value ) rt300@13: { rt300@13: if ( addChildValues_ ) rt300@13: childValues_.push_back( value ); rt300@13: else rt300@13: *document_ << value; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledStreamWriter::writeIndent() rt300@13: { rt300@13: /* rt300@13: Some comments in this method would have been nice. ;-) rt300@13: rt300@13: if ( !document_.empty() ) rt300@13: { rt300@13: char last = document_[document_.length()-1]; rt300@13: if ( last == ' ' ) // already indented rt300@13: return; rt300@13: if ( last != '\n' ) // Comments may add new-line rt300@13: *document_ << '\n'; rt300@13: } rt300@13: */ rt300@13: *document_ << '\n' << indentString_; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledStreamWriter::writeWithIndent( const std::string &value ) rt300@13: { rt300@13: writeIndent(); rt300@13: *document_ << value; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledStreamWriter::indent() rt300@13: { rt300@13: indentString_ += indentation_; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledStreamWriter::unindent() rt300@13: { rt300@13: assert( indentString_.size() >= indentation_.size() ); rt300@13: indentString_.resize( indentString_.size() - indentation_.size() ); rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledStreamWriter::writeCommentBeforeValue( const Value &root ) rt300@13: { rt300@13: if ( !root.hasComment( commentBefore ) ) rt300@13: return; rt300@13: *document_ << normalizeEOL( root.getComment( commentBefore ) ); rt300@13: *document_ << "\n"; rt300@13: } rt300@13: rt300@13: rt300@13: void rt300@13: StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root ) rt300@13: { rt300@13: if ( root.hasComment( commentAfterOnSameLine ) ) rt300@13: *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) ); rt300@13: rt300@13: if ( root.hasComment( commentAfter ) ) rt300@13: { rt300@13: *document_ << "\n"; rt300@13: *document_ << normalizeEOL( root.getComment( commentAfter ) ); rt300@13: *document_ << "\n"; rt300@13: } rt300@13: } rt300@13: rt300@13: rt300@13: bool rt300@13: StyledStreamWriter::hasCommentForValue( const Value &value ) rt300@13: { rt300@13: return value.hasComment( commentBefore ) rt300@13: || value.hasComment( commentAfterOnSameLine ) rt300@13: || value.hasComment( commentAfter ); rt300@13: } rt300@13: rt300@13: rt300@13: std::string rt300@13: StyledStreamWriter::normalizeEOL( const std::string &text ) rt300@13: { rt300@13: std::string normalized; rt300@13: normalized.reserve( text.length() ); rt300@13: const char *begin = text.c_str(); rt300@13: const char *end = begin + text.length(); rt300@13: const char *current = begin; rt300@13: while ( current != end ) rt300@13: { rt300@13: char c = *current++; rt300@13: if ( c == '\r' ) // mac or dos EOL rt300@13: { rt300@13: if ( *current == '\n' ) // convert dos EOL rt300@13: ++current; rt300@13: normalized += '\n'; rt300@13: } rt300@13: else // handle unix EOL & other char rt300@13: normalized += c; rt300@13: } rt300@13: return normalized; rt300@13: } rt300@13: rt300@13: rt300@13: std::ostream& operator<<( std::ostream &sout, const Value &root ) rt300@13: { rt300@13: Json::StyledStreamWriter writer; rt300@13: writer.write(sout, root); rt300@13: return sout; rt300@13: } rt300@13: rt300@13: rt300@13: } // namespace Json rt300@13: rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: // End of content of file: src/lib_json/json_writer.cpp rt300@13: // ////////////////////////////////////////////////////////////////////// rt300@13: rt300@13: rt300@13: rt300@13: rt300@13: