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