json_writer.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006 #if !defined(JSON_IS_AMALGAMATION)
00007 # include <json/writer.h>
00008 # include "json_tool.h"
00009 #endif // if !defined(JSON_IS_AMALGAMATION)
00010 #include <utility>
00011 #include <assert.h>
00012 #include <stdio.h>
00013 #include <string.h>
00014 #include <iostream>
00015 #include <sstream>
00016 #include <iomanip>
00017
00018 #if _MSC_VER >= 1400 // VC++ 8.0
00019 #pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
00020 #endif
00021
00022 namespace Json {
00023
00024 static bool containsControlCharacter( const char* str )
00025 {
00026 while ( *str )
00027 {
00028 if ( isControlCharacter( *(str++) ) )
00029 return true;
00030 }
00031 return false;
00032 }
00033
00034
00035 std::string valueToString( LargestInt value )
00036 {
00037 UIntToStringBuffer buffer;
00038 char *current = buffer + sizeof(buffer);
00039 bool isNegative = value < 0;
00040 if ( isNegative )
00041 value = -value;
00042 uintToString( LargestUInt(value), current );
00043 if ( isNegative )
00044 *--current = '-';
00045 assert( current >= buffer );
00046 return current;
00047 }
00048
00049
00050 std::string valueToString( LargestUInt value )
00051 {
00052 UIntToStringBuffer buffer;
00053 char *current = buffer + sizeof(buffer);
00054 uintToString( value, current );
00055 assert( current >= buffer );
00056 return current;
00057 }
00058
00059 #if defined(JSON_HAS_INT64)
00060
00061 std::string valueToString( Int value )
00062 {
00063 return valueToString( LargestInt(value) );
00064 }
00065
00066
00067 std::string valueToString( UInt value )
00068 {
00069 return valueToString( LargestUInt(value) );
00070 }
00071
00072 #endif // # if defined(JSON_HAS_INT64)
00073
00074
00075 std::string valueToString( double value )
00076 {
00077 char buffer[32];
00078 #if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
00079 sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
00080 #else
00081 sprintf(buffer, "%#.16g", value);
00082 #endif
00083 char* ch = buffer + strlen(buffer) - 1;
00084 if (*ch != '0') return buffer;
00085 while(ch > buffer && *ch == '0'){
00086 --ch;
00087 }
00088 char* last_nonzero = ch;
00089 while(ch >= buffer){
00090 switch(*ch){
00091 case '0':
00092 case '1':
00093 case '2':
00094 case '3':
00095 case '4':
00096 case '5':
00097 case '6':
00098 case '7':
00099 case '8':
00100 case '9':
00101 --ch;
00102 continue;
00103 case '.':
00104
00105 *(last_nonzero+2) = '\0';
00106 return buffer;
00107 default:
00108 return buffer;
00109 }
00110 }
00111 return buffer;
00112 }
00113
00114
00115 std::string valueToString( bool value )
00116 {
00117 return value ? "true" : "false";
00118 }
00119
00120 std::string valueToQuotedString( const char *value )
00121 {
00122
00123 if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
00124 return std::string("\"") + value + "\"";
00125
00126
00127
00128 std::string::size_type maxsize = strlen(value)*2 + 3;
00129 std::string result;
00130 result.reserve(maxsize);
00131 result += "\"";
00132 for (const char* c=value; *c != 0; ++c)
00133 {
00134 switch(*c)
00135 {
00136 case '\"':
00137 result += "\\\"";
00138 break;
00139 case '\\':
00140 result += "\\\\";
00141 break;
00142 case '\b':
00143 result += "\\b";
00144 break;
00145 case '\f':
00146 result += "\\f";
00147 break;
00148 case '\n':
00149 result += "\\n";
00150 break;
00151 case '\r':
00152 result += "\\r";
00153 break;
00154 case '\t':
00155 result += "\\t";
00156 break;
00157
00158
00159
00160
00161
00162
00163
00164
00165 default:
00166 if ( isControlCharacter( *c ) )
00167 {
00168 std::ostringstream oss;
00169 oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
00170 result += oss.str();
00171 }
00172 else
00173 {
00174 result += *c;
00175 }
00176 break;
00177 }
00178 }
00179 result += "\"";
00180 return result;
00181 }
00182
00183
00184
00185 Writer::~Writer()
00186 {
00187 }
00188
00189
00190
00191
00192
00193 FastWriter::FastWriter()
00194 : yamlCompatiblityEnabled_( false )
00195 {
00196 }
00197
00198
00199 void
00200 FastWriter::enableYAMLCompatibility()
00201 {
00202 yamlCompatiblityEnabled_ = true;
00203 }
00204
00205
00206 std::string
00207 FastWriter::write( const Value &root )
00208 {
00209 document_ = "";
00210 writeValue( root );
00211 document_ += "\n";
00212 return document_;
00213 }
00214
00215
00216 void
00217 FastWriter::writeValue( const Value &value )
00218 {
00219 switch ( value.type() )
00220 {
00221 case nullValue:
00222 document_ += "null";
00223 break;
00224 case intValue:
00225 document_ += valueToString( value.asLargestInt() );
00226 break;
00227 case uintValue:
00228 document_ += valueToString( value.asLargestUInt() );
00229 break;
00230 case realValue:
00231 document_ += valueToString( value.asDouble() );
00232 break;
00233 case stringValue:
00234 document_ += valueToQuotedString( value.asCString() );
00235 break;
00236 case booleanValue:
00237 document_ += valueToString( value.asBool() );
00238 break;
00239 case arrayValue:
00240 {
00241 document_ += "[";
00242 int size = value.size();
00243 for ( int index =0; index < size; ++index )
00244 {
00245 if ( index > 0 )
00246 document_ += ",";
00247 writeValue( value[index] );
00248 }
00249 document_ += "]";
00250 }
00251 break;
00252 case objectValue:
00253 {
00254 Value::Members members( value.getMemberNames() );
00255 document_ += "{";
00256 for ( Value::Members::iterator it = members.begin();
00257 it != members.end();
00258 ++it )
00259 {
00260 const std::string &name = *it;
00261 if ( it != members.begin() )
00262 document_ += ",";
00263 document_ += valueToQuotedString( name.c_str() );
00264 document_ += yamlCompatiblityEnabled_ ? ": "
00265 : ":";
00266 writeValue( value[name] );
00267 }
00268 document_ += "}";
00269 }
00270 break;
00271 }
00272 }
00273
00274
00275
00276
00277
00278 StyledWriter::StyledWriter()
00279 : rightMargin_( 74 )
00280 , indentSize_( 3 )
00281 {
00282 }
00283
00284
00285 std::string
00286 StyledWriter::write( const Value &root )
00287 {
00288 document_ = "";
00289 addChildValues_ = false;
00290 indentString_ = "";
00291 writeCommentBeforeValue( root );
00292 writeValue( root );
00293 writeCommentAfterValueOnSameLine( root );
00294 document_ += "\n";
00295 return document_;
00296 }
00297
00298
00299 void
00300 StyledWriter::writeValue( const Value &value )
00301 {
00302 switch ( value.type() )
00303 {
00304 case nullValue:
00305 pushValue( "null" );
00306 break;
00307 case intValue:
00308 pushValue( valueToString( value.asLargestInt() ) );
00309 break;
00310 case uintValue:
00311 pushValue( valueToString( value.asLargestUInt() ) );
00312 break;
00313 case realValue:
00314 pushValue( valueToString( value.asDouble() ) );
00315 break;
00316 case stringValue:
00317 pushValue( valueToQuotedString( value.asCString() ) );
00318 break;
00319 case booleanValue:
00320 pushValue( valueToString( value.asBool() ) );
00321 break;
00322 case arrayValue:
00323 writeArrayValue( value);
00324 break;
00325 case objectValue:
00326 {
00327 Value::Members members( value.getMemberNames() );
00328 if ( members.empty() )
00329 pushValue( "{}" );
00330 else
00331 {
00332 writeWithIndent( "{" );
00333 indent();
00334 Value::Members::iterator it = members.begin();
00335 for (;;)
00336 {
00337 const std::string &name = *it;
00338 const Value &childValue = value[name];
00339 writeCommentBeforeValue( childValue );
00340 writeWithIndent( valueToQuotedString( name.c_str() ) );
00341 document_ += " : ";
00342 writeValue( childValue );
00343 if ( ++it == members.end() )
00344 {
00345 writeCommentAfterValueOnSameLine( childValue );
00346 break;
00347 }
00348 document_ += ",";
00349 writeCommentAfterValueOnSameLine( childValue );
00350 }
00351 unindent();
00352 writeWithIndent( "}" );
00353 }
00354 }
00355 break;
00356 }
00357 }
00358
00359
00360 void
00361 StyledWriter::writeArrayValue( const Value &value )
00362 {
00363 unsigned size = value.size();
00364 if ( size == 0 )
00365 pushValue( "[]" );
00366 else
00367 {
00368 bool isArrayMultiLine = isMultineArray( value );
00369 if ( isArrayMultiLine )
00370 {
00371 writeWithIndent( "[" );
00372 indent();
00373 bool hasChildValue = !childValues_.empty();
00374 unsigned index =0;
00375 for (;;)
00376 {
00377 const Value &childValue = value[index];
00378 writeCommentBeforeValue( childValue );
00379 if ( hasChildValue )
00380 writeWithIndent( childValues_[index] );
00381 else
00382 {
00383 writeIndent();
00384 writeValue( childValue );
00385 }
00386 if ( ++index == size )
00387 {
00388 writeCommentAfterValueOnSameLine( childValue );
00389 break;
00390 }
00391 document_ += ",";
00392 writeCommentAfterValueOnSameLine( childValue );
00393 }
00394 unindent();
00395 writeWithIndent( "]" );
00396 }
00397 else
00398 {
00399 assert( childValues_.size() == size );
00400 document_ += "[ ";
00401 for ( unsigned index =0; index < size; ++index )
00402 {
00403 if ( index > 0 )
00404 document_ += ", ";
00405 document_ += childValues_[index];
00406 }
00407 document_ += " ]";
00408 }
00409 }
00410 }
00411
00412
00413 bool
00414 StyledWriter::isMultineArray( const Value &value )
00415 {
00416 int size = value.size();
00417 bool isMultiLine = size*3 >= rightMargin_ ;
00418 childValues_.clear();
00419 for ( int index =0; index < size && !isMultiLine; ++index )
00420 {
00421 const Value &childValue = value[index];
00422 isMultiLine = isMultiLine ||
00423 ( (childValue.isArray() || childValue.isObject()) &&
00424 childValue.size() > 0 );
00425 }
00426 if ( !isMultiLine )
00427 {
00428 childValues_.reserve( size );
00429 addChildValues_ = true;
00430 int lineLength = 4 + (size-1)*2;
00431 for ( int index =0; index < size && !isMultiLine; ++index )
00432 {
00433 writeValue( value[index] );
00434 lineLength += int( childValues_[index].length() );
00435 isMultiLine = isMultiLine && hasCommentForValue( value[index] );
00436 }
00437 addChildValues_ = false;
00438 isMultiLine = isMultiLine || lineLength >= rightMargin_;
00439 }
00440 return isMultiLine;
00441 }
00442
00443
00444 void
00445 StyledWriter::pushValue( const std::string &value )
00446 {
00447 if ( addChildValues_ )
00448 childValues_.push_back( value );
00449 else
00450 document_ += value;
00451 }
00452
00453
00454 void
00455 StyledWriter::writeIndent()
00456 {
00457 if ( !document_.empty() )
00458 {
00459 char last = document_[document_.length()-1];
00460 if ( last == ' ' )
00461 return;
00462 if ( last != '\n' )
00463 document_ += '\n';
00464 }
00465 document_ += indentString_;
00466 }
00467
00468
00469 void
00470 StyledWriter::writeWithIndent( const std::string &value )
00471 {
00472 writeIndent();
00473 document_ += value;
00474 }
00475
00476
00477 void
00478 StyledWriter::indent()
00479 {
00480 indentString_ += std::string( indentSize_, ' ' );
00481 }
00482
00483
00484 void
00485 StyledWriter::unindent()
00486 {
00487 assert( int(indentString_.size()) >= indentSize_ );
00488 indentString_.resize( indentString_.size() - indentSize_ );
00489 }
00490
00491
00492 void
00493 StyledWriter::writeCommentBeforeValue( const Value &root )
00494 {
00495 if ( !root.hasComment( commentBefore ) )
00496 return;
00497 document_ += normalizeEOL( root.getComment( commentBefore ) );
00498 document_ += "\n";
00499 }
00500
00501
00502 void
00503 StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
00504 {
00505 if ( root.hasComment( commentAfterOnSameLine ) )
00506 document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
00507
00508 if ( root.hasComment( commentAfter ) )
00509 {
00510 document_ += "\n";
00511 document_ += normalizeEOL( root.getComment( commentAfter ) );
00512 document_ += "\n";
00513 }
00514 }
00515
00516
00517 bool
00518 StyledWriter::hasCommentForValue( const Value &value )
00519 {
00520 return value.hasComment( commentBefore )
00521 || value.hasComment( commentAfterOnSameLine )
00522 || value.hasComment( commentAfter );
00523 }
00524
00525
00526 std::string
00527 StyledWriter::normalizeEOL( const std::string &text )
00528 {
00529 std::string normalized;
00530 normalized.reserve( text.length() );
00531 const char *begin = text.c_str();
00532 const char *end = begin + text.length();
00533 const char *current = begin;
00534 while ( current != end )
00535 {
00536 char c = *current++;
00537 if ( c == '\r' )
00538 {
00539 if ( *current == '\n' )
00540 ++current;
00541 normalized += '\n';
00542 }
00543 else
00544 normalized += c;
00545 }
00546 return normalized;
00547 }
00548
00549
00550
00551
00552
00553 StyledStreamWriter::StyledStreamWriter( std::string indentation )
00554 : document_(NULL)
00555 , rightMargin_( 74 )
00556 , indentation_( indentation )
00557 {
00558 }
00559
00560
00561 void
00562 StyledStreamWriter::write( std::ostream &out, const Value &root )
00563 {
00564 document_ = &out;
00565 addChildValues_ = false;
00566 indentString_ = "";
00567 writeCommentBeforeValue( root );
00568 writeValue( root );
00569 writeCommentAfterValueOnSameLine( root );
00570 *document_ << "\n";
00571 document_ = NULL;
00572 }
00573
00574
00575 void
00576 StyledStreamWriter::writeValue( const Value &value )
00577 {
00578 switch ( value.type() )
00579 {
00580 case nullValue:
00581 pushValue( "null" );
00582 break;
00583 case intValue:
00584 pushValue( valueToString( value.asLargestInt() ) );
00585 break;
00586 case uintValue:
00587 pushValue( valueToString( value.asLargestUInt() ) );
00588 break;
00589 case realValue:
00590 pushValue( valueToString( value.asDouble() ) );
00591 break;
00592 case stringValue:
00593 pushValue( valueToQuotedString( value.asCString() ) );
00594 break;
00595 case booleanValue:
00596 pushValue( valueToString( value.asBool() ) );
00597 break;
00598 case arrayValue:
00599 writeArrayValue( value);
00600 break;
00601 case objectValue:
00602 {
00603 Value::Members members( value.getMemberNames() );
00604 if ( members.empty() )
00605 pushValue( "{}" );
00606 else
00607 {
00608 writeWithIndent( "{" );
00609 indent();
00610 Value::Members::iterator it = members.begin();
00611 for (;;)
00612 {
00613 const std::string &name = *it;
00614 const Value &childValue = value[name];
00615 writeCommentBeforeValue( childValue );
00616 writeWithIndent( valueToQuotedString( name.c_str() ) );
00617 *document_ << " : ";
00618 writeValue( childValue );
00619 if ( ++it == members.end() )
00620 {
00621 writeCommentAfterValueOnSameLine( childValue );
00622 break;
00623 }
00624 *document_ << ",";
00625 writeCommentAfterValueOnSameLine( childValue );
00626 }
00627 unindent();
00628 writeWithIndent( "}" );
00629 }
00630 }
00631 break;
00632 }
00633 }
00634
00635
00636 void
00637 StyledStreamWriter::writeArrayValue( const Value &value )
00638 {
00639 unsigned size = value.size();
00640 if ( size == 0 )
00641 pushValue( "[]" );
00642 else
00643 {
00644 bool isArrayMultiLine = isMultineArray( value );
00645 if ( isArrayMultiLine )
00646 {
00647 writeWithIndent( "[" );
00648 indent();
00649 bool hasChildValue = !childValues_.empty();
00650 unsigned index =0;
00651 for (;;)
00652 {
00653 const Value &childValue = value[index];
00654 writeCommentBeforeValue( childValue );
00655 if ( hasChildValue )
00656 writeWithIndent( childValues_[index] );
00657 else
00658 {
00659 writeIndent();
00660 writeValue( childValue );
00661 }
00662 if ( ++index == size )
00663 {
00664 writeCommentAfterValueOnSameLine( childValue );
00665 break;
00666 }
00667 *document_ << ",";
00668 writeCommentAfterValueOnSameLine( childValue );
00669 }
00670 unindent();
00671 writeWithIndent( "]" );
00672 }
00673 else
00674 {
00675 assert( childValues_.size() == size );
00676 *document_ << "[ ";
00677 for ( unsigned index =0; index < size; ++index )
00678 {
00679 if ( index > 0 )
00680 *document_ << ", ";
00681 *document_ << childValues_[index];
00682 }
00683 *document_ << " ]";
00684 }
00685 }
00686 }
00687
00688
00689 bool
00690 StyledStreamWriter::isMultineArray( const Value &value )
00691 {
00692 int size = value.size();
00693 bool isMultiLine = size*3 >= rightMargin_ ;
00694 childValues_.clear();
00695 for ( int index =0; index < size && !isMultiLine; ++index )
00696 {
00697 const Value &childValue = value[index];
00698 isMultiLine = isMultiLine ||
00699 ( (childValue.isArray() || childValue.isObject()) &&
00700 childValue.size() > 0 );
00701 }
00702 if ( !isMultiLine )
00703 {
00704 childValues_.reserve( size );
00705 addChildValues_ = true;
00706 int lineLength = 4 + (size-1)*2;
00707 for ( int index =0; index < size && !isMultiLine; ++index )
00708 {
00709 writeValue( value[index] );
00710 lineLength += int( childValues_[index].length() );
00711 isMultiLine = isMultiLine && hasCommentForValue( value[index] );
00712 }
00713 addChildValues_ = false;
00714 isMultiLine = isMultiLine || lineLength >= rightMargin_;
00715 }
00716 return isMultiLine;
00717 }
00718
00719
00720 void
00721 StyledStreamWriter::pushValue( const std::string &value )
00722 {
00723 if ( addChildValues_ )
00724 childValues_.push_back( value );
00725 else
00726 *document_ << value;
00727 }
00728
00729
00730 void
00731 StyledStreamWriter::writeIndent()
00732 {
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745 *document_ << '\n' << indentString_;
00746 }
00747
00748
00749 void
00750 StyledStreamWriter::writeWithIndent( const std::string &value )
00751 {
00752 writeIndent();
00753 *document_ << value;
00754 }
00755
00756
00757 void
00758 StyledStreamWriter::indent()
00759 {
00760 indentString_ += indentation_;
00761 }
00762
00763
00764 void
00765 StyledStreamWriter::unindent()
00766 {
00767 assert( indentString_.size() >= indentation_.size() );
00768 indentString_.resize( indentString_.size() - indentation_.size() );
00769 }
00770
00771
00772 void
00773 StyledStreamWriter::writeCommentBeforeValue( const Value &root )
00774 {
00775 if ( !root.hasComment( commentBefore ) )
00776 return;
00777 *document_ << normalizeEOL( root.getComment( commentBefore ) );
00778 *document_ << "\n";
00779 }
00780
00781
00782 void
00783 StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
00784 {
00785 if ( root.hasComment( commentAfterOnSameLine ) )
00786 *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
00787
00788 if ( root.hasComment( commentAfter ) )
00789 {
00790 *document_ << "\n";
00791 *document_ << normalizeEOL( root.getComment( commentAfter ) );
00792 *document_ << "\n";
00793 }
00794 }
00795
00796
00797 bool
00798 StyledStreamWriter::hasCommentForValue( const Value &value )
00799 {
00800 return value.hasComment( commentBefore )
00801 || value.hasComment( commentAfterOnSameLine )
00802 || value.hasComment( commentAfter );
00803 }
00804
00805
00806 std::string
00807 StyledStreamWriter::normalizeEOL( const std::string &text )
00808 {
00809 std::string normalized;
00810 normalized.reserve( text.length() );
00811 const char *begin = text.c_str();
00812 const char *end = begin + text.length();
00813 const char *current = begin;
00814 while ( current != end )
00815 {
00816 char c = *current++;
00817 if ( c == '\r' )
00818 {
00819 if ( *current == '\n' )
00820 ++current;
00821 normalized += '\n';
00822 }
00823 else
00824 normalized += c;
00825 }
00826 return normalized;
00827 }
00828
00829
00830 std::ostream& operator<<( std::ostream &sout, const Value &root )
00831 {
00832 Json::StyledStreamWriter writer;
00833 writer.write(sout, root);
00834 return sout;
00835 }
00836
00837
00838 }