@@ -476,10 +476,291 @@ StyledWriter::normalizeEOL( const std::string &text )
476476 return normalized;
477477}
478478
479+
480+ // Class StyledStreamWriter
481+ // //////////////////////////////////////////////////////////////////
482+
483+ StyledStreamWriter::StyledStreamWriter ( std::string indentation )
484+ : document_(NULL )
485+ , rightMargin_( 74 )
486+ , indentation_( indentation )
487+ {
488+ }
489+
490+
491+ void
492+ StyledStreamWriter::write ( std::ostream &out, const Value &root )
493+ {
494+ document_ = &out;
495+ addChildValues_ = false ;
496+ indentString_ = " " ;
497+ writeCommentBeforeValue ( root );
498+ writeValue ( root );
499+ writeCommentAfterValueOnSameLine ( root );
500+ *document_ << " \n " ;
501+ document_ = NULL ; // Forget the stream, for safety.
502+ }
503+
504+
505+ void
506+ StyledStreamWriter::writeValue ( const Value &value )
507+ {
508+ switch ( value.type () )
509+ {
510+ case nullValue:
511+ pushValue ( " null" );
512+ break ;
513+ case intValue:
514+ pushValue ( valueToString ( value.asInt () ) );
515+ break ;
516+ case uintValue:
517+ pushValue ( valueToString ( value.asUInt () ) );
518+ break ;
519+ case realValue:
520+ pushValue ( valueToString ( value.asDouble () ) );
521+ break ;
522+ case stringValue:
523+ pushValue ( valueToQuotedString ( value.asCString () ) );
524+ break ;
525+ case booleanValue:
526+ pushValue ( valueToString ( value.asBool () ) );
527+ break ;
528+ case arrayValue:
529+ writeArrayValue ( value);
530+ break ;
531+ case objectValue:
532+ {
533+ Value::Members members ( value.getMemberNames () );
534+ if ( members.empty () )
535+ pushValue ( " {}" );
536+ else
537+ {
538+ writeWithIndent ( " {" );
539+ indent ();
540+ Value::Members::iterator it = members.begin ();
541+ while ( true )
542+ {
543+ const std::string &name = *it;
544+ const Value &childValue = value[name];
545+ writeCommentBeforeValue ( childValue );
546+ writeWithIndent ( valueToQuotedString ( name.c_str () ) );
547+ *document_ << " : " ;
548+ writeValue ( childValue );
549+ if ( ++it == members.end () )
550+ {
551+ writeCommentAfterValueOnSameLine ( childValue );
552+ break ;
553+ }
554+ *document_ << " ," ;
555+ writeCommentAfterValueOnSameLine ( childValue );
556+ }
557+ unindent ();
558+ writeWithIndent ( " }" );
559+ }
560+ }
561+ break ;
562+ }
563+ }
564+
565+
566+ void
567+ StyledStreamWriter::writeArrayValue ( const Value &value )
568+ {
569+ unsigned size = value.size ();
570+ if ( size == 0 )
571+ pushValue ( " []" );
572+ else
573+ {
574+ bool isArrayMultiLine = isMultineArray ( value );
575+ if ( isArrayMultiLine )
576+ {
577+ writeWithIndent ( " [" );
578+ indent ();
579+ bool hasChildValue = !childValues_.empty ();
580+ unsigned index =0 ;
581+ while ( true )
582+ {
583+ const Value &childValue = value[index];
584+ writeCommentBeforeValue ( childValue );
585+ if ( hasChildValue )
586+ writeWithIndent ( childValues_[index] );
587+ else
588+ {
589+ writeIndent ();
590+ writeValue ( childValue );
591+ }
592+ if ( ++index == size )
593+ {
594+ writeCommentAfterValueOnSameLine ( childValue );
595+ break ;
596+ }
597+ *document_ << " ," ;
598+ writeCommentAfterValueOnSameLine ( childValue );
599+ }
600+ unindent ();
601+ writeWithIndent ( " ]" );
602+ }
603+ else // output on a single line
604+ {
605+ assert ( childValues_.size () == size );
606+ *document_ << " [ " ;
607+ for ( unsigned index =0 ; index < size; ++index )
608+ {
609+ if ( index > 0 )
610+ *document_ << " , " ;
611+ *document_ << childValues_[index];
612+ }
613+ *document_ << " ]" ;
614+ }
615+ }
616+ }
617+
618+
619+ bool
620+ StyledStreamWriter::isMultineArray ( const Value &value )
621+ {
622+ int size = value.size ();
623+ bool isMultiLine = size*3 >= rightMargin_ ;
624+ childValues_.clear ();
625+ for ( int index =0 ; index < size && !isMultiLine; ++index )
626+ {
627+ const Value &childValue = value[index];
628+ isMultiLine = isMultiLine ||
629+ ( (childValue.isArray () || childValue.isObject ()) &&
630+ childValue.size () > 0 );
631+ }
632+ if ( !isMultiLine ) // check if line length > max line length
633+ {
634+ childValues_.reserve ( size );
635+ addChildValues_ = true ;
636+ int lineLength = 4 + (size-1 )*2 ; // '[ ' + ', '*n + ' ]'
637+ for ( int index =0 ; index < size && !isMultiLine; ++index )
638+ {
639+ writeValue ( value[index] );
640+ lineLength += int ( childValues_[index].length () );
641+ isMultiLine = isMultiLine && hasCommentForValue ( value[index] );
642+ }
643+ addChildValues_ = false ;
644+ isMultiLine = isMultiLine || lineLength >= rightMargin_;
645+ }
646+ return isMultiLine;
647+ }
648+
649+
650+ void
651+ StyledStreamWriter::pushValue ( const std::string &value )
652+ {
653+ if ( addChildValues_ )
654+ childValues_.push_back ( value );
655+ else
656+ *document_ << value;
657+ }
658+
659+
660+ void
661+ StyledStreamWriter::writeIndent ()
662+ {
663+ /*
664+ Some comments in this method would have been nice. ;-)
665+
666+ if ( !document_.empty() )
667+ {
668+ char last = document_[document_.length()-1];
669+ if ( last == ' ' ) // already indented
670+ return;
671+ if ( last != '\n' ) // Comments may add new-line
672+ *document_ << '\n';
673+ }
674+ */
675+ *document_ << indentString_;
676+ }
677+
678+
679+ void
680+ StyledStreamWriter::writeWithIndent ( const std::string &value )
681+ {
682+ writeIndent ();
683+ *document_ << value;
684+ }
685+
686+
687+ void
688+ StyledStreamWriter::indent ()
689+ {
690+ indentString_ += indentation_;
691+ }
692+
693+
694+ void
695+ StyledStreamWriter::unindent ()
696+ {
697+ assert ( indentString_.size () >= indentation_.size () );
698+ indentString_.resize ( indentString_.size () - indentation_.size () );
699+ }
700+
701+
702+ void
703+ StyledStreamWriter::writeCommentBeforeValue ( const Value &root )
704+ {
705+ if ( !root.hasComment ( commentBefore ) )
706+ return ;
707+ *document_ << normalizeEOL ( root.getComment ( commentBefore ) );
708+ *document_ << " \n " ;
709+ }
710+
711+
712+ void
713+ StyledStreamWriter::writeCommentAfterValueOnSameLine ( const Value &root )
714+ {
715+ if ( root.hasComment ( commentAfterOnSameLine ) )
716+ *document_ << " " + normalizeEOL ( root.getComment ( commentAfterOnSameLine ) );
717+
718+ if ( root.hasComment ( commentAfter ) )
719+ {
720+ *document_ << " \n " ;
721+ *document_ << normalizeEOL ( root.getComment ( commentAfter ) );
722+ *document_ << " \n " ;
723+ }
724+ }
725+
726+
727+ bool
728+ StyledStreamWriter::hasCommentForValue ( const Value &value )
729+ {
730+ return value.hasComment ( commentBefore )
731+ || value.hasComment ( commentAfterOnSameLine )
732+ || value.hasComment ( commentAfter );
733+ }
734+
735+
736+ std::string
737+ StyledStreamWriter::normalizeEOL ( const std::string &text )
738+ {
739+ std::string normalized;
740+ normalized.reserve ( text.length () );
741+ const char *begin = text.c_str ();
742+ const char *end = begin + text.length ();
743+ const char *current = begin;
744+ while ( current != end )
745+ {
746+ char c = *current++;
747+ if ( c == ' \r ' ) // mac or dos EOL
748+ {
749+ if ( *current == ' \n ' ) // convert dos EOL
750+ ++current;
751+ normalized += ' \n ' ;
752+ }
753+ else // handle unix EOL & other char
754+ normalized += c;
755+ }
756+ return normalized;
757+ }
758+
759+
479760std::ostream& operator <<( std::ostream &sout, const Value &root )
480761{
481- Json::StyledWriter writer;
482- sout << writer.write (root);
762+ Json::StyledStreamWriter writer;
763+ writer.write (sout, root);
483764 return sout;
484765}
485766
0 commit comments