001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.net.io;
019    
020    import java.io.FilterOutputStream;
021    import java.io.IOException;
022    import java.io.OutputStream;
023    
024    /***
025     * This class wraps an output stream, replacing all occurrences
026     * of <CR><LF> (carriage return followed by a linefeed),
027     * which is the NETASCII standard for representing a newline, with the
028     * local line separator representation.  You would use this class to
029     * implement ASCII file transfers requiring conversion from NETASCII.
030     * <p>
031     * Because of the translation process, a call to <code>flush()</code> will
032     * not flush the last byte written if that byte was a carriage
033     * return.  A call to {@link #close  close() }, however, will
034     * flush the carriage return.
035     * <p>
036     * <p>
037     * @author Daniel F. Savarese
038     ***/
039    
040    public final class FromNetASCIIOutputStream extends FilterOutputStream
041    {
042        private boolean __lastWasCR;
043    
044        /***
045         * Creates a FromNetASCIIOutputStream instance that wraps an existing
046         * OutputStream.
047         * <p>
048         * @param output  The OutputStream to wrap.
049         ***/
050        public FromNetASCIIOutputStream(OutputStream output)
051        {
052            super(output);
053            __lastWasCR = false;
054        }
055    
056    
057        private void __write(int ch) throws IOException
058        {
059            switch (ch)
060            {
061            case '\r':
062                __lastWasCR = true;
063                // Don't write anything.  We need to see if next one is linefeed
064                break;
065            case '\n':
066                if (__lastWasCR)
067                {
068                    out.write(FromNetASCIIInputStream._lineSeparatorBytes);
069                    __lastWasCR = false;
070                    break;
071                }
072                __lastWasCR = false;
073                out.write('\n');
074                break;
075            default:
076                if (__lastWasCR)
077                {
078                    out.write('\r');
079                    __lastWasCR = false;
080                }
081                out.write(ch);
082                break;
083            }
084        }
085    
086    
087        /***
088         * Writes a byte to the stream.    Note that a call to this method
089         * might not actually write a byte to the underlying stream until a
090         * subsequent character is written, from which it can be determined if
091         * a NETASCII line separator was encountered.
092         * This is transparent to the programmer and is only mentioned for
093         * completeness.
094         * <p>
095         * @param ch The byte to write.
096         * @exception IOException If an error occurs while writing to the underlying
097         *            stream.
098         ***/
099        @Override
100        public synchronized void write(int ch)
101        throws IOException
102        {
103            if (FromNetASCIIInputStream._noConversionRequired)
104            {
105                out.write(ch);
106                return ;
107            }
108    
109            __write(ch);
110        }
111    
112    
113        /***
114         * Writes a byte array to the stream.
115         * <p>
116         * @param buffer  The byte array to write.
117         * @exception IOException If an error occurs while writing to the underlying
118         *            stream.
119         ***/
120        @Override
121        public synchronized void write(byte buffer[])
122        throws IOException
123        {
124            write(buffer, 0, buffer.length);
125        }
126    
127    
128        /***
129         * Writes a number of bytes from a byte array to the stream starting from
130         * a given offset.
131         * <p>
132         * @param buffer  The byte array to write.
133         * @param offset  The offset into the array at which to start copying data.
134         * @param length  The number of bytes to write.
135         * @exception IOException If an error occurs while writing to the underlying
136         *            stream.
137         ***/
138        @Override
139        public synchronized void write(byte buffer[], int offset, int length)
140        throws IOException
141        {
142            if (FromNetASCIIInputStream._noConversionRequired)
143            {
144                // FilterOutputStream method is very slow.
145                //super.write(buffer, offset, length);
146                out.write(buffer, offset, length);
147                return ;
148            }
149    
150            while (length-- > 0)
151                __write(buffer[offset++]);
152        }
153    
154    
155        /***
156         * Closes the stream, writing all pending data.
157         * <p>
158         * @exception IOException  If an error occurs while closing the stream.
159         ***/
160        @Override
161        public synchronized void close()
162        throws IOException
163        {
164            if (FromNetASCIIInputStream._noConversionRequired)
165            {
166                super.close();
167                return ;
168            }
169    
170            if (__lastWasCR)
171                out.write('\r');
172            super.close();
173        }
174    }