00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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 *¤t )
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;
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
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
00147 if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
00148 return std::string("\"") + value + "\"";
00149
00150
00151
00152 unsigned maxsize = strlen(value)*2 + 3;
00153 std::string result;
00154 result.reserve(maxsize);
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
00182
00183
00184
00185
00186
00187
00188
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
00208
00209 Writer::~Writer()
00210 {
00211 }
00212
00213
00214
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
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
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 )
00451 {
00452 childValues_.reserve( size );
00453 addChildValues_ = true;
00454 int lineLength = 4 + (size-1)*2;
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 == ' ' )
00485 return;
00486 if ( last != '\n' )
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' )
00562 {
00563 if ( *current == '\n' )
00564 ++current;
00565 normalized += '\n';
00566 }
00567 else
00568 normalized += c;
00569 }
00570 return normalized;
00571 }
00572
00573
00574
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;
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
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 )
00727 {
00728 childValues_.reserve( size );
00729 addChildValues_ = true;
00730 int lineLength = 4 + (size-1)*2;
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
00759
00760
00761
00762
00763
00764
00765
00766
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' )
00842 {
00843 if ( *current == '\n' )
00844 ++current;
00845 normalized += '\n';
00846 }
00847 else
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 }