Drizzled Public API Documentation

json_writer.cpp
00001 /*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00002  * 
00003  *  JSON Library, originally from http://jsoncpp.sourceforge.net/
00004  *
00005  *  Copyright (C) 2011 Stewart Smith
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions are
00010  *  met:
00011  *
00012  *      * Redistributions of source code must retain the above copyright
00013  *  notice, this list of conditions and the following disclaimer.
00014  *
00015  *      * Redistributions in binary form must reproduce the above
00016  *  copyright notice, this list of conditions and the following disclaimer
00017  *  in the documentation and/or other materials provided with the
00018  *  distribution.
00019  *
00020  *      * The names of its contributors may not be used to endorse or
00021  *  promote products derived from this software without specific prior
00022  *  written permission.
00023  *
00024  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00025  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00026  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00027  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00028  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00029  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00030  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00031  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00032  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00033  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00034  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  */
00037 
00038 #include <plugin/json_server/json/writer.h>
00039 
00040 #include <cassert>
00041 #include <iomanip>
00042 #include <iostream>
00043 #include <sstream>
00044 #include <stdio.h>
00045 #include <string.h>
00046 #include <utility>
00047 namespace Json {
00048 
00049 static bool isControlCharacter(char ch)
00050 {
00051    return ch > 0 && ch <= 0x1F;
00052 }
00053 
00054 static bool containsControlCharacter( const char* str )
00055 {
00056    while ( *str ) 
00057    {
00058       if ( isControlCharacter( *(str++) ) )
00059          return true;
00060    }
00061    return false;
00062 }
00063 static void uintToString( unsigned int value, 
00064                           char *&current )
00065 {
00066    *--current = 0;
00067    do
00068    {
00069       *--current = (value % 10) + '0';
00070       value /= 10;
00071    }
00072    while ( value != 0 );
00073 }
00074 
00075 std::string valueToString( Int value )
00076 {
00077    char buffer[32];
00078    char *current = buffer + sizeof(buffer);
00079    bool isNegative = value < 0;
00080    if ( isNegative )
00081       value = -value;
00082    uintToString( UInt(value), current );
00083    if ( isNegative )
00084       *--current = '-';
00085    assert( current >= buffer );
00086    return current;
00087 }
00088 
00089 
00090 std::string valueToString( UInt value )
00091 {
00092    char buffer[32];
00093    char *current = buffer + sizeof(buffer);
00094    uintToString( value, current );
00095    assert( current >= buffer );
00096    return current;
00097 }
00098 
00099 std::string valueToString( double value )
00100 {
00101    char buffer[32];
00102 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 
00103    sprintf_s(buffer, sizeof(buffer), "%#.16g", value); 
00104 #else 
00105    sprintf(buffer, "%#.16g", value); 
00106 #endif
00107    char* ch = buffer + strlen(buffer) - 1;
00108    if (*ch != '0') return buffer; // nothing to truncate, so save time
00109    while(ch > buffer && *ch == '0'){
00110      --ch;
00111    }
00112    char* last_nonzero = ch;
00113    while(ch >= buffer){
00114      switch(*ch){
00115      case '0':
00116      case '1':
00117      case '2':
00118      case '3':
00119      case '4':
00120      case '5':
00121      case '6':
00122      case '7':
00123      case '8':
00124      case '9':
00125        --ch;
00126        continue;
00127      case '.':
00128        // Truncate zeroes to save bytes in output, but keep one.
00129        *(last_nonzero+2) = '\0';
00130        return buffer;
00131      default:
00132        return buffer;
00133      }
00134    }
00135    return buffer;
00136 }
00137 
00138 
00139 std::string valueToString( bool value )
00140 {
00141    return value ? "true" : "false";
00142 }
00143 
00144 std::string valueToQuotedString( const char *value )
00145 {
00146    // Not sure how to handle unicode...
00147    if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
00148       return std::string("\"") + value + "\"";
00149    // We have to walk value and escape any special characters.
00150    // Appending to std::string is not efficient, but this should be rare.
00151    // (Note: forward slashes are *not* rare, but I am not escaping them.)
00152    unsigned maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
00153    std::string result;
00154    result.reserve(maxsize); // to avoid lots of mallocs
00155    result += "\"";
00156    for (const char* c=value; *c != 0; ++c)
00157    {
00158       switch(*c)
00159       {
00160          case '\"':
00161             result += "\\\"";
00162             break;
00163          case '\\':
00164             result += "\\\\";
00165             break;
00166          case '\b':
00167             result += "\\b";
00168             break;
00169          case '\f':
00170             result += "\\f";
00171             break;
00172          case '\n':
00173             result += "\\n";
00174             break;
00175          case '\r':
00176             result += "\\r";
00177             break;
00178          case '\t':
00179             result += "\\t";
00180             break;
00181          //case '/':
00182             // Even though \/ is considered a legal escape in JSON, a bare
00183             // slash is also legal, so I see no reason to escape it.
00184             // (I hope I am not misunderstanding something.
00185             // blep notes: actually escaping \/ may be useful in javascript to avoid </ 
00186             // sequence.
00187             // Should add a flag to allow this compatibility mode and prevent this 
00188             // sequence from occurring.
00189          default:
00190             if ( isControlCharacter( *c ) )
00191             {
00192                std::ostringstream oss;
00193                oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
00194                result += oss.str();
00195             }
00196             else
00197             {
00198                result += *c;
00199             }
00200             break;
00201       }
00202    }
00203    result += "\"";
00204    return result;
00205 }
00206 
00207 // Class Writer
00208 // //////////////////////////////////////////////////////////////////
00209 Writer::~Writer()
00210 {
00211 }
00212 
00213 
00214 // Class FastWriter
00215 // //////////////////////////////////////////////////////////////////
00216 
00217 FastWriter::FastWriter()
00218    : yamlCompatiblityEnabled_( false )
00219 {
00220 }
00221 
00222 
00223 void 
00224 FastWriter::enableYAMLCompatibility()
00225 {
00226    yamlCompatiblityEnabled_ = true;
00227 }
00228 
00229 
00230 std::string 
00231 FastWriter::write( const Value &root )
00232 {
00233    document_ = "";
00234    writeValue( root );
00235    document_ += "\n";
00236    return document_;
00237 }
00238 
00239 
00240 void 
00241 FastWriter::writeValue( const Value &value )
00242 {
00243    switch ( value.type() )
00244    {
00245    case nullValue:
00246       document_ += "null";
00247       break;
00248    case intValue:
00249       document_ += valueToString( value.asInt() );
00250       break;
00251    case uintValue:
00252       document_ += valueToString( value.asUInt() );
00253       break;
00254    case realValue:
00255       document_ += valueToString( value.asDouble() );
00256       break;
00257    case stringValue:
00258       document_ += valueToQuotedString( value.asCString() );
00259       break;
00260    case booleanValue:
00261       document_ += valueToString( value.asBool() );
00262       break;
00263    case arrayValue:
00264       {
00265          document_ += "[";
00266          int size = value.size();
00267          for ( int index =0; index < size; ++index )
00268          {
00269             if ( index > 0 )
00270                document_ += ",";
00271             writeValue( value[index] );
00272          }
00273          document_ += "]";
00274       }
00275       break;
00276    case objectValue:
00277       {
00278          Value::Members members( value.getMemberNames() );
00279          document_ += "{";
00280          for ( Value::Members::iterator it = members.begin(); 
00281                it != members.end(); 
00282                ++it )
00283          {
00284             const std::string &name = *it;
00285             if ( it != members.begin() )
00286                document_ += ",";
00287             document_ += valueToQuotedString( name.c_str() );
00288             document_ += yamlCompatiblityEnabled_ ? ": " 
00289                                                   : ":";
00290             writeValue( value[name] );
00291          }
00292          document_ += "}";
00293       }
00294       break;
00295    }
00296 }
00297 
00298 
00299 // Class StyledWriter
00300 // //////////////////////////////////////////////////////////////////
00301 
00302 StyledWriter::StyledWriter()
00303    : rightMargin_( 74 )
00304    , indentSize_( 3 )
00305 {
00306 }
00307 
00308 
00309 std::string 
00310 StyledWriter::write( const Value &root )
00311 {
00312    document_ = "";
00313    addChildValues_ = false;
00314    indentString_ = "";
00315    writeCommentBeforeValue( root );
00316    writeValue( root );
00317    writeCommentAfterValueOnSameLine( root );
00318    document_ += "\n";
00319    return document_;
00320 }
00321 
00322 
00323 void 
00324 StyledWriter::writeValue( const Value &value )
00325 {
00326    switch ( value.type() )
00327    {
00328    case nullValue:
00329       pushValue( "null" );
00330       break;
00331    case intValue:
00332       pushValue( valueToString( value.asInt() ) );
00333       break;
00334    case uintValue:
00335       pushValue( valueToString( value.asUInt() ) );
00336       break;
00337    case realValue:
00338       pushValue( valueToString( value.asDouble() ) );
00339       break;
00340    case stringValue:
00341       pushValue( valueToQuotedString( value.asCString() ) );
00342       break;
00343    case booleanValue:
00344       pushValue( valueToString( value.asBool() ) );
00345       break;
00346    case arrayValue:
00347       writeArrayValue( value);
00348       break;
00349    case objectValue:
00350       {
00351          Value::Members members( value.getMemberNames() );
00352          if ( members.empty() )
00353             pushValue( "{}" );
00354          else
00355          {
00356             writeWithIndent( "{" );
00357             indent();
00358             Value::Members::iterator it = members.begin();
00359             while ( true )
00360             {
00361                const std::string &name = *it;
00362                const Value &childValue = value[name];
00363                writeCommentBeforeValue( childValue );
00364                writeWithIndent( valueToQuotedString( name.c_str() ) );
00365                document_ += " : ";
00366                writeValue( childValue );
00367                if ( ++it == members.end() )
00368                {
00369                   writeCommentAfterValueOnSameLine( childValue );
00370                   break;
00371                }
00372                document_ += ",";
00373                writeCommentAfterValueOnSameLine( childValue );
00374             }
00375             unindent();
00376             writeWithIndent( "}" );
00377          }
00378       }
00379       break;
00380    }
00381 }
00382 
00383 
00384 void 
00385 StyledWriter::writeArrayValue( const Value &value )
00386 {
00387    unsigned size = value.size();
00388    if ( size == 0 )
00389       pushValue( "[]" );
00390    else
00391    {
00392       bool isArrayMultiLine = isMultineArray( value );
00393       if ( isArrayMultiLine )
00394       {
00395          writeWithIndent( "[" );
00396          indent();
00397          bool hasChildValue = !childValues_.empty();
00398          unsigned index =0;
00399          while ( true )
00400          {
00401             const Value &childValue = value[index];
00402             writeCommentBeforeValue( childValue );
00403             if ( hasChildValue )
00404                writeWithIndent( childValues_[index] );
00405             else
00406             {
00407                writeIndent();
00408                writeValue( childValue );
00409             }
00410             if ( ++index == size )
00411             {
00412                writeCommentAfterValueOnSameLine( childValue );
00413                break;
00414             }
00415             document_ += ",";
00416             writeCommentAfterValueOnSameLine( childValue );
00417          }
00418          unindent();
00419          writeWithIndent( "]" );
00420       }
00421       else // output on a single line
00422       {
00423          assert( childValues_.size() == size );
00424          document_ += "[ ";
00425          for ( unsigned index =0; index < size; ++index )
00426          {
00427             if ( index > 0 )
00428                document_ += ", ";
00429             document_ += childValues_[index];
00430          }
00431          document_ += " ]";
00432       }
00433    }
00434 }
00435 
00436 
00437 bool 
00438 StyledWriter::isMultineArray( const Value &value )
00439 {
00440    int size = value.size();
00441    bool isMultiLine = size*3 >= rightMargin_ ;
00442    childValues_.clear();
00443    for ( int index =0; index < size  &&  !isMultiLine; ++index )
00444    {
00445       const Value &childValue = value[index];
00446       isMultiLine = isMultiLine  ||
00447                      ( (childValue.isArray()  ||  childValue.isObject())  &&  
00448                         childValue.size() > 0 );
00449    }
00450    if ( !isMultiLine ) // check if line length > max line length
00451    {
00452       childValues_.reserve( size );
00453       addChildValues_ = true;
00454       int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
00455       for ( int index =0; index < size  &&  !isMultiLine; ++index )
00456       {
00457          writeValue( value[index] );
00458          lineLength += int( childValues_[index].length() );
00459          isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
00460       }
00461       addChildValues_ = false;
00462       isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
00463    }
00464    return isMultiLine;
00465 }
00466 
00467 
00468 void 
00469 StyledWriter::pushValue( const std::string &value )
00470 {
00471    if ( addChildValues_ )
00472       childValues_.push_back( value );
00473    else
00474       document_ += value;
00475 }
00476 
00477 
00478 void 
00479 StyledWriter::writeIndent()
00480 {
00481    if ( !document_.empty() )
00482    {
00483       char last = document_[document_.length()-1];
00484       if ( last == ' ' )     // already indented
00485          return;
00486       if ( last != '\n' )    // Comments may add new-line
00487          document_ += '\n';
00488    }
00489    document_ += indentString_;
00490 }
00491 
00492 
00493 void 
00494 StyledWriter::writeWithIndent( const std::string &value )
00495 {
00496    writeIndent();
00497    document_ += value;
00498 }
00499 
00500 
00501 void 
00502 StyledWriter::indent()
00503 {
00504    indentString_ += std::string( indentSize_, ' ' );
00505 }
00506 
00507 
00508 void 
00509 StyledWriter::unindent()
00510 {
00511    assert( int(indentString_.size()) >= indentSize_ );
00512    indentString_.resize( indentString_.size() - indentSize_ );
00513 }
00514 
00515 
00516 void 
00517 StyledWriter::writeCommentBeforeValue( const Value &root )
00518 {
00519    if ( !root.hasComment( commentBefore ) )
00520       return;
00521    document_ += normalizeEOL( root.getComment( commentBefore ) );
00522    document_ += "\n";
00523 }
00524 
00525 
00526 void 
00527 StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
00528 {
00529    if ( root.hasComment( commentAfterOnSameLine ) )
00530       document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
00531 
00532    if ( root.hasComment( commentAfter ) )
00533    {
00534       document_ += "\n";
00535       document_ += normalizeEOL( root.getComment( commentAfter ) );
00536       document_ += "\n";
00537    }
00538 }
00539 
00540 
00541 bool 
00542 StyledWriter::hasCommentForValue( const Value &value )
00543 {
00544    return value.hasComment( commentBefore )
00545           ||  value.hasComment( commentAfterOnSameLine )
00546           ||  value.hasComment( commentAfter );
00547 }
00548 
00549 
00550 std::string 
00551 StyledWriter::normalizeEOL( const std::string &text )
00552 {
00553    std::string normalized;
00554    normalized.reserve( text.length() );
00555    const char *begin = text.c_str();
00556    const char *end = begin + text.length();
00557    const char *current = begin;
00558    while ( current != end )
00559    {
00560       char c = *current++;
00561       if ( c == '\r' ) // mac or dos EOL
00562       {
00563          if ( *current == '\n' ) // convert dos EOL
00564             ++current;
00565          normalized += '\n';
00566       }
00567       else // handle unix EOL & other char
00568          normalized += c;
00569    }
00570    return normalized;
00571 }
00572 
00573 
00574 // Class StyledStreamWriter
00575 // //////////////////////////////////////////////////////////////////
00576 
00577 StyledStreamWriter::StyledStreamWriter( std::string indentation )
00578    : document_(NULL)
00579    , rightMargin_( 74 )
00580    , indentation_( indentation )
00581 {
00582 }
00583 
00584 
00585 void
00586 StyledStreamWriter::write( std::ostream &out, const Value &root )
00587 {
00588    document_ = &out;
00589    addChildValues_ = false;
00590    indentString_ = "";
00591    writeCommentBeforeValue( root );
00592    writeValue( root );
00593    writeCommentAfterValueOnSameLine( root );
00594    *document_ << "\n";
00595    document_ = NULL; // Forget the stream, for safety.
00596 }
00597 
00598 
00599 void 
00600 StyledStreamWriter::writeValue( const Value &value )
00601 {
00602    switch ( value.type() )
00603    {
00604    case nullValue:
00605       pushValue( "null" );
00606       break;
00607    case intValue:
00608       pushValue( valueToString( value.asInt() ) );
00609       break;
00610    case uintValue:
00611       pushValue( valueToString( value.asUInt() ) );
00612       break;
00613    case realValue:
00614       pushValue( valueToString( value.asDouble() ) );
00615       break;
00616    case stringValue:
00617       pushValue( valueToQuotedString( value.asCString() ) );
00618       break;
00619    case booleanValue:
00620       pushValue( valueToString( value.asBool() ) );
00621       break;
00622    case arrayValue:
00623       writeArrayValue( value);
00624       break;
00625    case objectValue:
00626       {
00627          Value::Members members( value.getMemberNames() );
00628          if ( members.empty() )
00629             pushValue( "{}" );
00630          else
00631          {
00632             writeWithIndent( "{" );
00633             indent();
00634             Value::Members::iterator it = members.begin();
00635             while ( true )
00636             {
00637                const std::string &name = *it;
00638                const Value &childValue = value[name];
00639                writeCommentBeforeValue( childValue );
00640                writeWithIndent( valueToQuotedString( name.c_str() ) );
00641                *document_ << " : ";
00642                writeValue( childValue );
00643                if ( ++it == members.end() )
00644                {
00645                   writeCommentAfterValueOnSameLine( childValue );
00646                   break;
00647                }
00648                *document_ << ",";
00649                writeCommentAfterValueOnSameLine( childValue );
00650             }
00651             unindent();
00652             writeWithIndent( "}" );
00653          }
00654       }
00655       break;
00656    }
00657 }
00658 
00659 
00660 void 
00661 StyledStreamWriter::writeArrayValue( const Value &value )
00662 {
00663    unsigned size = value.size();
00664    if ( size == 0 )
00665       pushValue( "[]" );
00666    else
00667    {
00668       bool isArrayMultiLine = isMultineArray( value );
00669       if ( isArrayMultiLine )
00670       {
00671          writeWithIndent( "[" );
00672          indent();
00673          bool hasChildValue = !childValues_.empty();
00674          unsigned index =0;
00675          while ( true )
00676          {
00677             const Value &childValue = value[index];
00678             writeCommentBeforeValue( childValue );
00679             if ( hasChildValue )
00680                writeWithIndent( childValues_[index] );
00681             else
00682             {
00683          writeIndent();
00684                writeValue( childValue );
00685             }
00686             if ( ++index == size )
00687             {
00688                writeCommentAfterValueOnSameLine( childValue );
00689                break;
00690             }
00691             *document_ << ",";
00692             writeCommentAfterValueOnSameLine( childValue );
00693          }
00694          unindent();
00695          writeWithIndent( "]" );
00696       }
00697       else // output on a single line
00698       {
00699          assert( childValues_.size() == size );
00700          *document_ << "[ ";
00701          for ( unsigned index =0; index < size; ++index )
00702          {
00703             if ( index > 0 )
00704                *document_ << ", ";
00705             *document_ << childValues_[index];
00706          }
00707          *document_ << " ]";
00708       }
00709    }
00710 }
00711 
00712 
00713 bool 
00714 StyledStreamWriter::isMultineArray( const Value &value )
00715 {
00716    int size = value.size();
00717    bool isMultiLine = size*3 >= rightMargin_ ;
00718    childValues_.clear();
00719    for ( int index =0; index < size  &&  !isMultiLine; ++index )
00720    {
00721       const Value &childValue = value[index];
00722       isMultiLine = isMultiLine  ||
00723                      ( (childValue.isArray()  ||  childValue.isObject())  &&  
00724                         childValue.size() > 0 );
00725    }
00726    if ( !isMultiLine ) // check if line length > max line length
00727    {
00728       childValues_.reserve( size );
00729       addChildValues_ = true;
00730       int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
00731       for ( int index =0; index < size  &&  !isMultiLine; ++index )
00732       {
00733          writeValue( value[index] );
00734          lineLength += int( childValues_[index].length() );
00735          isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
00736       }
00737       addChildValues_ = false;
00738       isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
00739    }
00740    return isMultiLine;
00741 }
00742 
00743 
00744 void 
00745 StyledStreamWriter::pushValue( const std::string &value )
00746 {
00747    if ( addChildValues_ )
00748       childValues_.push_back( value );
00749    else
00750       *document_ << value;
00751 }
00752 
00753 
00754 void 
00755 StyledStreamWriter::writeIndent()
00756 {
00757   /*
00758     Some comments in this method would have been nice. ;-)
00759 
00760    if ( !document_.empty() )
00761    {
00762       char last = document_[document_.length()-1];
00763       if ( last == ' ' )     // already indented
00764          return;
00765       if ( last != '\n' )    // Comments may add new-line
00766          *document_ << '\n';
00767    }
00768   */
00769    *document_ << '\n' << indentString_;
00770 }
00771 
00772 
00773 void 
00774 StyledStreamWriter::writeWithIndent( const std::string &value )
00775 {
00776    writeIndent();
00777    *document_ << value;
00778 }
00779 
00780 
00781 void 
00782 StyledStreamWriter::indent()
00783 {
00784    indentString_ += indentation_;
00785 }
00786 
00787 
00788 void 
00789 StyledStreamWriter::unindent()
00790 {
00791    assert( indentString_.size() >= indentation_.size() );
00792    indentString_.resize( indentString_.size() - indentation_.size() );
00793 }
00794 
00795 
00796 void 
00797 StyledStreamWriter::writeCommentBeforeValue( const Value &root )
00798 {
00799    if ( !root.hasComment( commentBefore ) )
00800       return;
00801    *document_ << normalizeEOL( root.getComment( commentBefore ) );
00802    *document_ << "\n";
00803 }
00804 
00805 
00806 void 
00807 StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
00808 {
00809    if ( root.hasComment( commentAfterOnSameLine ) )
00810       *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
00811 
00812    if ( root.hasComment( commentAfter ) )
00813    {
00814       *document_ << "\n";
00815       *document_ << normalizeEOL( root.getComment( commentAfter ) );
00816       *document_ << "\n";
00817    }
00818 }
00819 
00820 
00821 bool 
00822 StyledStreamWriter::hasCommentForValue( const Value &value )
00823 {
00824    return value.hasComment( commentBefore )
00825           ||  value.hasComment( commentAfterOnSameLine )
00826           ||  value.hasComment( commentAfter );
00827 }
00828 
00829 
00830 std::string 
00831 StyledStreamWriter::normalizeEOL( const std::string &text )
00832 {
00833    std::string normalized;
00834    normalized.reserve( text.length() );
00835    const char *begin = text.c_str();
00836    const char *end = begin + text.length();
00837    const char *current = begin;
00838    while ( current != end )
00839    {
00840       char c = *current++;
00841       if ( c == '\r' ) // mac or dos EOL
00842       {
00843          if ( *current == '\n' ) // convert dos EOL
00844             ++current;
00845          normalized += '\n';
00846       }
00847       else // handle unix EOL & other char
00848          normalized += c;
00849    }
00850    return normalized;
00851 }
00852 
00853 
00854 std::ostream& operator<<( std::ostream &sout, const Value &root )
00855 {
00856    Json::StyledStreamWriter writer;
00857    writer.write(sout, root);
00858    return sout;
00859 }
00860 
00861 
00862 } // namespace Json