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.FilterInputStream;
021    import java.io.IOException;
022    import java.io.InputStream;
023    
024    /***
025     * This class wraps an input stream, replacing all singly occurring
026     * <LF> (linefeed) characters with <CR><LF> (carriage return
027     * followed by linefeed), which is the NETASCII standard for representing
028     * a newline.
029     * You would use this class to implement ASCII file transfers requiring
030     * conversion to NETASCII.
031     * <p>
032     * <p>
033     * @author Daniel F. Savarese
034     ***/
035    
036    public final class ToNetASCIIInputStream extends FilterInputStream
037    {
038        private static final int __NOTHING_SPECIAL = 0;
039        private static final int __LAST_WAS_CR = 1;
040        private static final int __LAST_WAS_NL = 2;
041        private int __status;
042    
043        /***
044         * Creates a ToNetASCIIInputStream instance that wraps an existing
045         * InputStream.
046         * <p>
047         * @param input  The InputStream to .
048         ***/
049        public ToNetASCIIInputStream(InputStream input)
050        {
051            super(input);
052            __status = __NOTHING_SPECIAL;
053        }
054    
055    
056        /***
057         * Reads and returns the next byte in the stream.  If the end of the
058         * message has been reached, returns -1.
059         * <p>
060         * @return The next character in the stream. Returns -1 if the end of the
061         *          stream has been reached.
062         * @exception IOException If an error occurs while reading the underlying
063         *            stream.
064         ***/
065        @Override
066        public int read() throws IOException
067        {
068            int ch;
069    
070            if (__status == __LAST_WAS_NL)
071            {
072                __status = __NOTHING_SPECIAL;
073                return '\n';
074            }
075    
076            ch = in.read();
077    
078            switch (ch)
079            {
080            case '\r':
081                __status = __LAST_WAS_CR;
082                return '\r';
083            case '\n':
084                if (__status != __LAST_WAS_CR)
085                {
086                    __status = __LAST_WAS_NL;
087                    return '\r';
088                }
089                //$FALL-THROUGH$
090            default:
091                __status = __NOTHING_SPECIAL;
092                return ch;
093            }
094            // statement not reached
095            //return ch;
096        }
097    
098    
099        /***
100         * Reads the next number of bytes from the stream into an array and
101         * returns the number of bytes read.  Returns -1 if the end of the
102         * stream has been reached.
103         * <p>
104         * @param buffer  The byte array in which to store the data.
105         * @return The number of bytes read. Returns -1 if the
106         *          end of the message has been reached.
107         * @exception IOException If an error occurs in reading the underlying
108         *            stream.
109         ***/
110        @Override
111        public int read(byte buffer[]) throws IOException
112        {
113            return read(buffer, 0, buffer.length);
114        }
115    
116    
117        /***
118         * Reads the next number of bytes from the stream into an array and returns
119         * the number of bytes read.  Returns -1 if the end of the
120         * message has been reached.  The characters are stored in the array
121         * starting from the given offset and up to the length specified.
122         * <p>
123         * @param buffer The byte array in which to store the data.
124         * @param offset  The offset into the array at which to start storing data.
125         * @param length   The number of bytes to read.
126         * @return The number of bytes read. Returns -1 if the
127         *          end of the stream has been reached.
128         * @exception IOException If an error occurs while reading the underlying
129         *            stream.
130         ***/
131        @Override
132        public int read(byte buffer[], int offset, int length) throws IOException
133        {
134            int ch, off;
135    
136            if (length < 1)
137                return 0;
138    
139            ch = available();
140    
141            if (length > ch)
142                length = ch;
143    
144            // If nothing is available, block to read only one character
145            if (length < 1)
146                length = 1;
147    
148            if ((ch = read()) == -1)
149                return -1;
150    
151            off = offset;
152    
153            do
154            {
155                buffer[offset++] = (byte)ch;
156            }
157            while (--length > 0 && (ch = read()) != -1);
158    
159            return (offset - off);
160        }
161    
162        /*** Returns false.  Mark is not supported. ***/
163        @Override
164        public boolean markSupported()
165        {
166            return false;
167        }
168    
169        @Override
170        public int available() throws IOException
171        {
172            int result;
173    
174            result = in.available();
175    
176            if (__status == __LAST_WAS_NL)
177                return (result + 1);
178    
179            return result;
180        }
181    }