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
 |