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