001package votorola.g.io; // Copyright 2007, 2012, Michael Allan.  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA 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 VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE.
002
003import java.io.*;
004import java.nio.*;
005import java.nio.charset.*;
006import votorola.g.lang.*;
007
008
009/** An output stream that writes to a string builder.
010  */
011public @ThreadRestricted @Warning("dead code") final class StringSink extends OutputStream
012{
013
014
015    /** Constructs a StringSink.
016      *
017      *     @see #builder()
018      *     @see #charset()
019      */
020    public StringSink( StringBuilder _builder, Charset _charset )
021    {
022        b = _builder;
023        charset = _charset;
024
025        decoder = charset.newDecoder();
026    }
027
028
029
030   // ------------------------------------------------------------------------------------
031
032
033    /** The underlying string builder.
034      */
035    public StringBuilder builder() { return b; }
036
037
038        private final StringBuilder b;
039
040
041
042    /** The character set in which this stream's bytes are encoded.
043      */
044    public Charset charset() { return charset; }
045
046
047        private final Charset charset;
048
049
050
051    /** Resets this stream discarding any output in the string builder.
052      */
053    public void reset()
054    {
055        decoder.reset();
056        byteBuffer.clear();
057        charBuffer.clear();
058        StringBuilderX.clear( b );
059    }
060
061
062
063   // - O u t p u t - S t r e a m --------------------------------------------------------
064
065
066    public @Override void flush() throws CharacterCodingException
067    {
068        flushByteBuffer( /*endOfInput*/true );
069    }
070
071
072
073    public @Override void write( final int c ) throws CharacterCodingException
074    {
075        if( byteBuffer.position() >= byteBuffer.limit() ) flushByteBuffer( /*endOfInput*/false );
076        byteBuffer.put( (byte)c );
077    }
078
079
080
081//// P r i v a t e ///////////////////////////////////////////////////////////////////////
082
083
084    private final ByteBuffer byteBuffer = ByteBuffer.allocate( /*capacity*/16 );
085
086
087
088    private final CharBuffer charBuffer = CharBuffer.allocate( /*capacity*/16 );
089
090
091
092    private final CharsetDecoder decoder;
093
094
095
096    private void flushByteBuffer( final boolean endOfInput ) throws CharacterCodingException
097    {
098        CoderResult result;
099
100      // byte to char
101      // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
102        byteBuffer.flip();
103        result = decoder.decode( byteBuffer, charBuffer, endOfInput );
104        byteBuffer.compact();
105        if( result.isError() ) result.throwException();
106
107      // char to string
108      // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
109        flushCharBuffer();
110        if( endOfInput )
111        {
112            result = decoder.flush( charBuffer );
113            if( result.isError() ) result.throwException();
114
115            flushCharBuffer();
116        }
117    }
118
119
120
121    private void flushCharBuffer()
122    {
123        charBuffer.flip();
124        for( int p = charBuffer.position(), l = charBuffer.limit(); p < l; ++p )
125        {
126            b.append( charBuffer.charAt( p ));
127        }
128        charBuffer.clear();
129    }
130
131
132
133}