mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			858 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			858 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2007-2010 Baptiste Lepilleur
 | |
| // Distributed under MIT license, or public domain if desired and
 | |
| // recognized in your jurisdiction.
 | |
| // See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
 | |
| 
 | |
| /*
 | |
| Permission is hereby granted, free of charge, to any person obtaining
 | |
| a copy of this software and associated documentation files (the
 | |
| "Software"), to deal in the Software without restriction, including
 | |
| without limitation the rights to use, copy, modify, merge, publish,
 | |
| distribute, sublicense, and/or sell copies of the Software, and to
 | |
| permit persons to whom the Software is furnished to do so, subject to
 | |
| the following conditions:
 | |
| 
 | |
| The above copyright notice and this permission notice shall be
 | |
| included in all copies or substantial portions of the Software.
 | |
| 
 | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | |
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 | |
| LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | |
| OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | |
| WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | |
| */
 | |
| 
 | |
| // Source - https://github.com/Ij888/ApacheCordovaRecipes/blob/6e8a2c1d9de7302f74bc3dbac54a021f0499bbb3/jqmsandbox/plugins/cordova-plugin-globalization/src/blackberry10/native/public/json_writer.cpp
 | |
| 
 | |
| #include <json/writer.h>
 | |
| #include <utility>
 | |
| #include <assert.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <iostream>
 | |
| #include <sstream>
 | |
| #include <iomanip>
 | |
| 
 | |
| #if _MSC_VER >= 1400 // VC++ 8.0
 | |
| #pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
 | |
| #endif
 | |
| 
 | |
| namespace Json {
 | |
| 
 | |
| static bool isControlCharacter(char ch)
 | |
| {
 | |
|    return ch > 0 && ch <= 0x1F;
 | |
| }
 | |
| 
 | |
| static bool containsControlCharacter( const char* str )
 | |
| {
 | |
|    while ( *str ) 
 | |
|    {
 | |
|       if ( isControlCharacter( *(str++) ) )
 | |
|          return true;
 | |
|    }
 | |
|    return false;
 | |
| }
 | |
| static void uintToString( unsigned int value, 
 | |
|                           char *¤t )
 | |
| {
 | |
|    *--current = 0;
 | |
|    do
 | |
|    {
 | |
|       *--current = (value % 10) + '0';
 | |
|       value /= 10;
 | |
|    }
 | |
|    while ( value != 0 );
 | |
| }
 | |
| 
 | |
| std::string valueToString( Int value )
 | |
| {
 | |
|    char buffer[32];
 | |
|    char *current = buffer + sizeof(buffer);
 | |
|    bool isNegative = value < 0;
 | |
|    if ( isNegative )
 | |
|       value = -value;
 | |
|    uintToString( UInt(value), current );
 | |
|    if ( isNegative )
 | |
|       *--current = '-';
 | |
|    assert( current >= buffer );
 | |
|    return current;
 | |
| }
 | |
| 
 | |
| 
 | |
| std::string valueToString( UInt value )
 | |
| {
 | |
|    char buffer[32];
 | |
|    char *current = buffer + sizeof(buffer);
 | |
|    uintToString( value, current );
 | |
|    assert( current >= buffer );
 | |
|    return current;
 | |
| }
 | |
| 
 | |
| std::string valueToString( double value )
 | |
| {
 | |
|    char buffer[32];
 | |
| #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 
 | |
|    sprintf_s(buffer, sizeof(buffer), "%#.16g", value); 
 | |
| #else	
 | |
|    sprintf(buffer, "%#.16g", value); 
 | |
| #endif
 | |
|    char* ch = buffer + strlen(buffer) - 1;
 | |
|    if (*ch != '0') return buffer; // nothing to truncate, so save time
 | |
|    while(ch > buffer && *ch == '0'){
 | |
|      --ch;
 | |
|    }
 | |
|    char* last_nonzero = ch;
 | |
|    while(ch >= buffer){
 | |
|      switch(*ch){
 | |
|      case '0':
 | |
|      case '1':
 | |
|      case '2':
 | |
|      case '3':
 | |
|      case '4':
 | |
|      case '5':
 | |
|      case '6':
 | |
|      case '7':
 | |
|      case '8':
 | |
|      case '9':
 | |
|        --ch;
 | |
|        continue;
 | |
|      case '.':
 | |
|        // Truncate zeroes to save bytes in output, but keep one.
 | |
|        *(last_nonzero+2) = '\0';
 | |
|        return buffer;
 | |
|      default:
 | |
|        return buffer;
 | |
|      }
 | |
|    }
 | |
|    return buffer;
 | |
| }
 | |
| 
 | |
| 
 | |
| std::string valueToString( bool value )
 | |
| {
 | |
|    return value ? "true" : "false";
 | |
| }
 | |
| 
 | |
| std::string valueToQuotedString( const char *value )
 | |
| {
 | |
|    // Not sure how to handle unicode...
 | |
|    if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
 | |
|       return std::string("\"") + value + "\"";
 | |
|    // We have to walk value and escape any special characters.
 | |
|    // Appending to std::string is not efficient, but this should be rare.
 | |
|    // (Note: forward slashes are *not* rare, but I am not escaping them.)
 | |
|    unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
 | |
|    std::string result;
 | |
|    result.reserve(maxsize); // to avoid lots of mallocs
 | |
|    result += "\"";
 | |
|    for (const char* c=value; *c != 0; ++c)
 | |
|    {
 | |
|       switch(*c)
 | |
|       {
 | |
|          case '\"':
 | |
|             result += "\\\"";
 | |
|             break;
 | |
|          case '\\':
 | |
|             result += "\\\\";
 | |
|             break;
 | |
|          case '\b':
 | |
|             result += "\\b";
 | |
|             break;
 | |
|          case '\f':
 | |
|             result += "\\f";
 | |
|             break;
 | |
|          case '\n':
 | |
|             result += "\\n";
 | |
|             break;
 | |
|          case '\r':
 | |
|             result += "\\r";
 | |
|             break;
 | |
|          case '\t':
 | |
|             result += "\\t";
 | |
|             break;
 | |
|          //case '/':
 | |
|             // Even though \/ is considered a legal escape in JSON, a bare
 | |
|             // slash is also legal, so I see no reason to escape it.
 | |
|             // (I hope I am not misunderstanding something.
 | |
|             // blep notes: actually escaping \/ may be useful in javascript to avoid </ 
 | |
|             // sequence.
 | |
|             // Should add a flag to allow this compatibility mode and prevent this 
 | |
|             // sequence from occurring.
 | |
|          default:
 | |
|             if ( isControlCharacter( *c ) )
 | |
|             {
 | |
|                std::ostringstream oss;
 | |
|                oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
 | |
|                result += oss.str();
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                result += *c;
 | |
|             }
 | |
|             break;
 | |
|       }
 | |
|    }
 | |
|    result += "\"";
 | |
|    return result;
 | |
| }
 | |
| 
 | |
| // Class Writer
 | |
| // //////////////////////////////////////////////////////////////////
 | |
| Writer::~Writer()
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| // Class FastWriter
 | |
| // //////////////////////////////////////////////////////////////////
 | |
| 
 | |
| FastWriter::FastWriter()
 | |
|    : yamlCompatiblityEnabled_( false )
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| FastWriter::enableYAMLCompatibility()
 | |
| {
 | |
|    yamlCompatiblityEnabled_ = true;
 | |
| }
 | |
| 
 | |
| 
 | |
| std::string 
 | |
| FastWriter::write( const Value &root )
 | |
| {
 | |
|    document_ = "";
 | |
|    writeValue( root );
 | |
|    document_ += "\n";
 | |
|    return document_;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| FastWriter::writeValue( const Value &value )
 | |
| {
 | |
|    switch ( value.type() )
 | |
|    {
 | |
|    case nullValue:
 | |
|       document_ += "null";
 | |
|       break;
 | |
|    case intValue:
 | |
|       document_ += valueToString( value.asInt() );
 | |
|       break;
 | |
|    case uintValue:
 | |
|       document_ += valueToString( value.asUInt() );
 | |
|       break;
 | |
|    case realValue:
 | |
|       document_ += valueToString( value.asDouble() );
 | |
|       break;
 | |
|    case stringValue:
 | |
|       document_ += valueToQuotedString( value.asCString() );
 | |
|       break;
 | |
|    case booleanValue:
 | |
|       document_ += valueToString( value.asBool() );
 | |
|       break;
 | |
|    case arrayValue:
 | |
|       {
 | |
|          document_ += "[";
 | |
|          int size = value.size();
 | |
|          for ( int index =0; index < size; ++index )
 | |
|          {
 | |
|             if ( index > 0 )
 | |
|                document_ += ",";
 | |
|             writeValue( value[index] );
 | |
|          }
 | |
|          document_ += "]";
 | |
|       }
 | |
|       break;
 | |
|    case objectValue:
 | |
|       {
 | |
|          Value::Members members( value.getMemberNames() );
 | |
|          document_ += "{";
 | |
|          for ( Value::Members::iterator it = members.begin(); 
 | |
|                it != members.end(); 
 | |
|                ++it )
 | |
|          {
 | |
|             const std::string &name = *it;
 | |
|             if ( it != members.begin() )
 | |
|                document_ += ",";
 | |
|             document_ += valueToQuotedString( name.c_str() );
 | |
|             document_ += yamlCompatiblityEnabled_ ? ": " 
 | |
|                                                   : ":";
 | |
|             writeValue( value[name] );
 | |
|          }
 | |
|          document_ += "}";
 | |
|       }
 | |
|       break;
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| // Class StyledWriter
 | |
| // //////////////////////////////////////////////////////////////////
 | |
| 
 | |
| StyledWriter::StyledWriter()
 | |
|    : rightMargin_( 74 )
 | |
|    , indentSize_( 3 )
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| std::string 
 | |
| StyledWriter::write( const Value &root )
 | |
| {
 | |
|    document_ = "";
 | |
|    addChildValues_ = false;
 | |
|    indentString_ = "";
 | |
|    writeCommentBeforeValue( root );
 | |
|    writeValue( root );
 | |
|    writeCommentAfterValueOnSameLine( root );
 | |
|    document_ += "\n";
 | |
|    return document_;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledWriter::writeValue( const Value &value )
 | |
| {
 | |
|    switch ( value.type() )
 | |
|    {
 | |
|    case nullValue:
 | |
|       pushValue( "null" );
 | |
|       break;
 | |
|    case intValue:
 | |
|       pushValue( valueToString( value.asInt() ) );
 | |
|       break;
 | |
|    case uintValue:
 | |
|       pushValue( valueToString( value.asUInt() ) );
 | |
|       break;
 | |
|    case realValue:
 | |
|       pushValue( valueToString( value.asDouble() ) );
 | |
|       break;
 | |
|    case stringValue:
 | |
|       pushValue( valueToQuotedString( value.asCString() ) );
 | |
|       break;
 | |
|    case booleanValue:
 | |
|       pushValue( valueToString( value.asBool() ) );
 | |
|       break;
 | |
|    case arrayValue:
 | |
|       writeArrayValue( value);
 | |
|       break;
 | |
|    case objectValue:
 | |
|       {
 | |
|          Value::Members members( value.getMemberNames() );
 | |
|          if ( members.empty() )
 | |
|             pushValue( "{}" );
 | |
|          else
 | |
|          {
 | |
|             writeWithIndent( "{" );
 | |
|             indent();
 | |
|             Value::Members::iterator it = members.begin();
 | |
|             while ( true )
 | |
|             {
 | |
|                const std::string &name = *it;
 | |
|                const Value &childValue = value[name];
 | |
|                writeCommentBeforeValue( childValue );
 | |
|                writeWithIndent( valueToQuotedString( name.c_str() ) );
 | |
|                document_ += " : ";
 | |
|                writeValue( childValue );
 | |
|                if ( ++it == members.end() )
 | |
|                {
 | |
|                   writeCommentAfterValueOnSameLine( childValue );
 | |
|                   break;
 | |
|                }
 | |
|                document_ += ",";
 | |
|                writeCommentAfterValueOnSameLine( childValue );
 | |
|             }
 | |
|             unindent();
 | |
|             writeWithIndent( "}" );
 | |
|          }
 | |
|       }
 | |
|       break;
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledWriter::writeArrayValue( const Value &value )
 | |
| {
 | |
|    unsigned size = value.size();
 | |
|    if ( size == 0 )
 | |
|       pushValue( "[]" );
 | |
|    else
 | |
|    {
 | |
|       bool isArrayMultiLine = isMultineArray( value );
 | |
|       if ( isArrayMultiLine )
 | |
|       {
 | |
|          writeWithIndent( "[" );
 | |
|          indent();
 | |
|          bool hasChildValue = !childValues_.empty();
 | |
|          unsigned index =0;
 | |
|          while ( true )
 | |
|          {
 | |
|             const Value &childValue = value[index];
 | |
|             writeCommentBeforeValue( childValue );
 | |
|             if ( hasChildValue )
 | |
|                writeWithIndent( childValues_[index] );
 | |
|             else
 | |
|             {
 | |
|                writeIndent();
 | |
|                writeValue( childValue );
 | |
|             }
 | |
|             if ( ++index == size )
 | |
|             {
 | |
|                writeCommentAfterValueOnSameLine( childValue );
 | |
|                break;
 | |
|             }
 | |
|             document_ += ",";
 | |
|             writeCommentAfterValueOnSameLine( childValue );
 | |
|          }
 | |
|          unindent();
 | |
|          writeWithIndent( "]" );
 | |
|       }
 | |
|       else // output on a single line
 | |
|       {
 | |
|          assert( childValues_.size() == size );
 | |
|          document_ += "[ ";
 | |
|          for ( unsigned index =0; index < size; ++index )
 | |
|          {
 | |
|             if ( index > 0 )
 | |
|                document_ += ", ";
 | |
|             document_ += childValues_[index];
 | |
|          }
 | |
|          document_ += " ]";
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| bool 
 | |
| StyledWriter::isMultineArray( const Value &value )
 | |
| {
 | |
|    int size = value.size();
 | |
|    bool isMultiLine = size*3 >= rightMargin_ ;
 | |
|    childValues_.clear();
 | |
|    for ( int index =0; index < size  &&  !isMultiLine; ++index )
 | |
|    {
 | |
|       const Value &childValue = value[index];
 | |
|       isMultiLine = isMultiLine  ||
 | |
|                      ( (childValue.isArray()  ||  childValue.isObject())  &&  
 | |
|                         childValue.size() > 0 );
 | |
|    }
 | |
|    if ( !isMultiLine ) // check if line length > max line length
 | |
|    {
 | |
|       childValues_.reserve( size );
 | |
|       addChildValues_ = true;
 | |
|       int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
 | |
|       for ( int index =0; index < size  &&  !isMultiLine; ++index )
 | |
|       {
 | |
|          writeValue( value[index] );
 | |
|          lineLength += int( childValues_[index].length() );
 | |
|          isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
 | |
|       }
 | |
|       addChildValues_ = false;
 | |
|       isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
 | |
|    }
 | |
|    return isMultiLine;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledWriter::pushValue( const std::string &value )
 | |
| {
 | |
|    if ( addChildValues_ )
 | |
|       childValues_.push_back( value );
 | |
|    else
 | |
|       document_ += value;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledWriter::writeIndent()
 | |
| {
 | |
|    if ( !document_.empty() )
 | |
|    {
 | |
|       char last = document_[document_.length()-1];
 | |
|       if ( last == ' ' )     // already indented
 | |
|          return;
 | |
|       if ( last != '\n' )    // Comments may add new-line
 | |
|          document_ += '\n';
 | |
|    }
 | |
|    document_ += indentString_;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledWriter::writeWithIndent( const std::string &value )
 | |
| {
 | |
|    writeIndent();
 | |
|    document_ += value;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledWriter::indent()
 | |
| {
 | |
|    indentString_ += std::string( indentSize_, ' ' );
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledWriter::unindent()
 | |
| {
 | |
|    assert( int(indentString_.size()) >= indentSize_ );
 | |
|    indentString_.resize( indentString_.size() - indentSize_ );
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledWriter::writeCommentBeforeValue( const Value &root )
 | |
| {
 | |
|    if ( !root.hasComment( commentBefore ) )
 | |
|       return;
 | |
|    document_ += normalizeEOL( root.getComment( commentBefore ) );
 | |
|    document_ += "\n";
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
 | |
| {
 | |
|    if ( root.hasComment( commentAfterOnSameLine ) )
 | |
|       document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
 | |
| 
 | |
|    if ( root.hasComment( commentAfter ) )
 | |
|    {
 | |
|       document_ += "\n";
 | |
|       document_ += normalizeEOL( root.getComment( commentAfter ) );
 | |
|       document_ += "\n";
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| bool 
 | |
| StyledWriter::hasCommentForValue( const Value &value )
 | |
| {
 | |
|    return value.hasComment( commentBefore )
 | |
|           ||  value.hasComment( commentAfterOnSameLine )
 | |
|           ||  value.hasComment( commentAfter );
 | |
| }
 | |
| 
 | |
| 
 | |
| std::string 
 | |
| StyledWriter::normalizeEOL( const std::string &text )
 | |
| {
 | |
|    std::string normalized;
 | |
|    normalized.reserve( text.length() );
 | |
|    const char *begin = text.c_str();
 | |
|    const char *end = begin + text.length();
 | |
|    const char *current = begin;
 | |
|    while ( current != end )
 | |
|    {
 | |
|       char c = *current++;
 | |
|       if ( c == '\r' ) // mac or dos EOL
 | |
|       {
 | |
|          if ( *current == '\n' ) // convert dos EOL
 | |
|             ++current;
 | |
|          normalized += '\n';
 | |
|       }
 | |
|       else // handle unix EOL & other char
 | |
|          normalized += c;
 | |
|    }
 | |
|    return normalized;
 | |
| }
 | |
| 
 | |
| 
 | |
| // Class StyledStreamWriter
 | |
| // //////////////////////////////////////////////////////////////////
 | |
| 
 | |
| StyledStreamWriter::StyledStreamWriter( std::string indentation )
 | |
|    : document_(NULL)
 | |
|    , rightMargin_( 74 )
 | |
|    , indentation_( indentation )
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| void
 | |
| StyledStreamWriter::write( std::ostream &out, const Value &root )
 | |
| {
 | |
|    document_ = &out;
 | |
|    addChildValues_ = false;
 | |
|    indentString_ = "";
 | |
|    writeCommentBeforeValue( root );
 | |
|    writeValue( root );
 | |
|    writeCommentAfterValueOnSameLine( root );
 | |
|    *document_ << "\n";
 | |
|    document_ = NULL; // Forget the stream, for safety.
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledStreamWriter::writeValue( const Value &value )
 | |
| {
 | |
|    switch ( value.type() )
 | |
|    {
 | |
|    case nullValue:
 | |
|       pushValue( "null" );
 | |
|       break;
 | |
|    case intValue:
 | |
|       pushValue( valueToString( value.asInt() ) );
 | |
|       break;
 | |
|    case uintValue:
 | |
|       pushValue( valueToString( value.asUInt() ) );
 | |
|       break;
 | |
|    case realValue:
 | |
|       pushValue( valueToString( value.asDouble() ) );
 | |
|       break;
 | |
|    case stringValue:
 | |
|       pushValue( valueToQuotedString( value.asCString() ) );
 | |
|       break;
 | |
|    case booleanValue:
 | |
|       pushValue( valueToString( value.asBool() ) );
 | |
|       break;
 | |
|    case arrayValue:
 | |
|       writeArrayValue( value);
 | |
|       break;
 | |
|    case objectValue:
 | |
|       {
 | |
|          Value::Members members( value.getMemberNames() );
 | |
|          if ( members.empty() )
 | |
|             pushValue( "{}" );
 | |
|          else
 | |
|          {
 | |
|             writeWithIndent( "{" );
 | |
|             indent();
 | |
|             Value::Members::iterator it = members.begin();
 | |
|             while ( true )
 | |
|             {
 | |
|                const std::string &name = *it;
 | |
|                const Value &childValue = value[name];
 | |
|                writeCommentBeforeValue( childValue );
 | |
|                writeWithIndent( valueToQuotedString( name.c_str() ) );
 | |
|                *document_ << " : ";
 | |
|                writeValue( childValue );
 | |
|                if ( ++it == members.end() )
 | |
|                {
 | |
|                   writeCommentAfterValueOnSameLine( childValue );
 | |
|                   break;
 | |
|                }
 | |
|                *document_ << ",";
 | |
|                writeCommentAfterValueOnSameLine( childValue );
 | |
|             }
 | |
|             unindent();
 | |
|             writeWithIndent( "}" );
 | |
|          }
 | |
|       }
 | |
|       break;
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledStreamWriter::writeArrayValue( const Value &value )
 | |
| {
 | |
|    unsigned size = value.size();
 | |
|    if ( size == 0 )
 | |
|       pushValue( "[]" );
 | |
|    else
 | |
|    {
 | |
|       bool isArrayMultiLine = isMultineArray( value );
 | |
|       if ( isArrayMultiLine )
 | |
|       {
 | |
|          writeWithIndent( "[" );
 | |
|          indent();
 | |
|          bool hasChildValue = !childValues_.empty();
 | |
|          unsigned index =0;
 | |
|          while ( true )
 | |
|          {
 | |
|             const Value &childValue = value[index];
 | |
|             writeCommentBeforeValue( childValue );
 | |
|             if ( hasChildValue )
 | |
|                writeWithIndent( childValues_[index] );
 | |
|             else
 | |
|             {
 | |
| 	       writeIndent();
 | |
|                writeValue( childValue );
 | |
|             }
 | |
|             if ( ++index == size )
 | |
|             {
 | |
|                writeCommentAfterValueOnSameLine( childValue );
 | |
|                break;
 | |
|             }
 | |
|             *document_ << ",";
 | |
|             writeCommentAfterValueOnSameLine( childValue );
 | |
|          }
 | |
|          unindent();
 | |
|          writeWithIndent( "]" );
 | |
|       }
 | |
|       else // output on a single line
 | |
|       {
 | |
|          assert( childValues_.size() == size );
 | |
|          *document_ << "[ ";
 | |
|          for ( unsigned index =0; index < size; ++index )
 | |
|          {
 | |
|             if ( index > 0 )
 | |
|                *document_ << ", ";
 | |
|             *document_ << childValues_[index];
 | |
|          }
 | |
|          *document_ << " ]";
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| bool 
 | |
| StyledStreamWriter::isMultineArray( const Value &value )
 | |
| {
 | |
|    int size = value.size();
 | |
|    bool isMultiLine = size*3 >= rightMargin_ ;
 | |
|    childValues_.clear();
 | |
|    for ( int index =0; index < size  &&  !isMultiLine; ++index )
 | |
|    {
 | |
|       const Value &childValue = value[index];
 | |
|       isMultiLine = isMultiLine  ||
 | |
|                      ( (childValue.isArray()  ||  childValue.isObject())  &&  
 | |
|                         childValue.size() > 0 );
 | |
|    }
 | |
|    if ( !isMultiLine ) // check if line length > max line length
 | |
|    {
 | |
|       childValues_.reserve( size );
 | |
|       addChildValues_ = true;
 | |
|       int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
 | |
|       for ( int index =0; index < size  &&  !isMultiLine; ++index )
 | |
|       {
 | |
|          writeValue( value[index] );
 | |
|          lineLength += int( childValues_[index].length() );
 | |
|          isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
 | |
|       }
 | |
|       addChildValues_ = false;
 | |
|       isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
 | |
|    }
 | |
|    return isMultiLine;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledStreamWriter::pushValue( const std::string &value )
 | |
| {
 | |
|    if ( addChildValues_ )
 | |
|       childValues_.push_back( value );
 | |
|    else
 | |
|       *document_ << value;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledStreamWriter::writeIndent()
 | |
| {
 | |
|   /*
 | |
|     Some comments in this method would have been nice. ;-)
 | |
| 
 | |
|    if ( !document_.empty() )
 | |
|    {
 | |
|       char last = document_[document_.length()-1];
 | |
|       if ( last == ' ' )     // already indented
 | |
|          return;
 | |
|       if ( last != '\n' )    // Comments may add new-line
 | |
|          *document_ << '\n';
 | |
|    }
 | |
|   */
 | |
|    *document_ << '\n' << indentString_;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledStreamWriter::writeWithIndent( const std::string &value )
 | |
| {
 | |
|    writeIndent();
 | |
|    *document_ << value;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledStreamWriter::indent()
 | |
| {
 | |
|    indentString_ += indentation_;
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledStreamWriter::unindent()
 | |
| {
 | |
|    assert( indentString_.size() >= indentation_.size() );
 | |
|    indentString_.resize( indentString_.size() - indentation_.size() );
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledStreamWriter::writeCommentBeforeValue( const Value &root )
 | |
| {
 | |
|    if ( !root.hasComment( commentBefore ) )
 | |
|       return;
 | |
|    *document_ << normalizeEOL( root.getComment( commentBefore ) );
 | |
|    *document_ << "\n";
 | |
| }
 | |
| 
 | |
| 
 | |
| void 
 | |
| StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
 | |
| {
 | |
|    if ( root.hasComment( commentAfterOnSameLine ) )
 | |
|       *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
 | |
| 
 | |
|    if ( root.hasComment( commentAfter ) )
 | |
|    {
 | |
|       *document_ << "\n";
 | |
|       *document_ << normalizeEOL( root.getComment( commentAfter ) );
 | |
|       *document_ << "\n";
 | |
|    }
 | |
| }
 | |
| 
 | |
| 
 | |
| bool 
 | |
| StyledStreamWriter::hasCommentForValue( const Value &value )
 | |
| {
 | |
|    return value.hasComment( commentBefore )
 | |
|           ||  value.hasComment( commentAfterOnSameLine )
 | |
|           ||  value.hasComment( commentAfter );
 | |
| }
 | |
| 
 | |
| 
 | |
| std::string 
 | |
| StyledStreamWriter::normalizeEOL( const std::string &text )
 | |
| {
 | |
|    std::string normalized;
 | |
|    normalized.reserve( text.length() );
 | |
|    const char *begin = text.c_str();
 | |
|    const char *end = begin + text.length();
 | |
|    const char *current = begin;
 | |
|    while ( current != end )
 | |
|    {
 | |
|       char c = *current++;
 | |
|       if ( c == '\r' ) // mac or dos EOL
 | |
|       {
 | |
|          if ( *current == '\n' ) // convert dos EOL
 | |
|             ++current;
 | |
|          normalized += '\n';
 | |
|       }
 | |
|       else // handle unix EOL & other char
 | |
|          normalized += c;
 | |
|    }
 | |
|    return normalized;
 | |
| }
 | |
| 
 | |
| 
 | |
| std::ostream& operator<<( std::ostream &sout, const Value &root )
 | |
| {
 | |
|    Json::StyledStreamWriter writer;
 | |
|    writer.write(sout, root);
 | |
|    return sout;
 | |
| }
 | |
| 
 | |
| 
 | |
| } // namespace Json
 |