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