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.IOException;
021    import java.io.InputStream;
022    import java.io.PushbackInputStream;
023    
024    /***
025     * This class wraps an input 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     * <p>
032     * @author Daniel F. Savarese
033     ***/
034    
035    public final class FromNetASCIIInputStream extends PushbackInputStream
036    {
037        static final boolean _noConversionRequired;
038        static final String _lineSeparator;
039        static final byte[] _lineSeparatorBytes;
040    
041        static {
042            _lineSeparator = System.getProperty("line.separator");
043            _noConversionRequired = _lineSeparator.equals("\r\n");
044            _lineSeparatorBytes = _lineSeparator.getBytes();
045        }
046    
047        private int __length = 0;
048    
049        /***
050         * Returns true if the NetASCII line separator differs from the system
051         * line separator, false if they are the same.  This method is useful
052         * to determine whether or not you need to instantiate a
053         * FromNetASCIIInputStream object.
054         * <p>
055         * @return True if the NETASCII line separator differs from the local
056         *   system line separator, false if they are the same.
057         ***/
058        public static final boolean isConversionRequired()
059        {
060            return !_noConversionRequired;
061        }
062    
063        /***
064         * Creates a FromNetASCIIInputStream instance that wraps an existing
065         * InputStream.
066         ***/
067        public FromNetASCIIInputStream(InputStream input)
068        {
069            super(input, _lineSeparatorBytes.length + 1);
070        }
071    
072    
073        private int __read() throws IOException
074        {
075            int ch;
076    
077            ch = super.read();
078    
079            if (ch == '\r')
080            {
081                ch = super.read();
082                if (ch == '\n')
083                {
084                    unread(_lineSeparatorBytes);
085                    ch = super.read();
086                    // This is a kluge for read(byte[], ...) to read the right amount
087                    --__length;
088                }
089                else
090                {
091                    if (ch != -1)
092                        unread(ch);
093                    return '\r';
094                }
095            }
096    
097            return ch;
098        }
099    
100    
101        /***
102         * Reads and returns the next byte in the stream.  If the end of the
103         * message has been reached, returns -1.  Note that a call to this method
104         * may result in multiple reads from the underlying input stream in order
105         * to convert NETASCII line separators to the local line separator format.
106         * This is transparent to the programmer and is only mentioned for
107         * completeness.
108         * <p>
109         * @return The next character in the stream. Returns -1 if the end of the
110         *          stream has been reached.
111         * @exception IOException If an error occurs while reading the underlying
112         *            stream.
113         ***/
114        @Override
115        public int read() throws IOException
116        {
117            if (_noConversionRequired)
118                return super.read();
119    
120            return __read();
121        }
122    
123    
124        /***
125         * Reads the next number of bytes from the stream into an array and
126         * returns the number of bytes read.  Returns -1 if the end of the
127         * stream has been reached.
128         * <p>
129         * @param buffer  The byte array in which to store the data.
130         * @return The number of bytes read. Returns -1 if the
131         *          end of the message has been reached.
132         * @exception IOException If an error occurs in reading the underlying
133         *            stream.
134         ***/
135        @Override
136        public int read(byte buffer[]) throws IOException
137        {
138            return read(buffer, 0, buffer.length);
139        }
140    
141    
142        /***
143         * Reads the next number of bytes from the stream into an array and returns
144         * the number of bytes read.  Returns -1 if the end of the
145         * message has been reached.  The characters are stored in the array
146         * starting from the given offset and up to the length specified.
147         * <p>
148         * @param buffer The byte array in which to store the data.
149         * @param offset  The offset into the array at which to start storing data.
150         * @param length   The number of bytes to read.
151         * @return The number of bytes read. Returns -1 if the
152         *          end of the stream has been reached.
153         * @exception IOException If an error occurs while reading the underlying
154         *            stream.
155         ***/
156        @Override
157        public int read(byte buffer[], int offset, int length) throws IOException
158        {
159            if (_noConversionRequired)
160                return super.read(buffer, offset, length);
161    
162            if (length < 1)
163                return 0;
164    
165            int ch, off;
166    
167            ch = available();
168    
169            __length = (length > ch ? ch : length);
170    
171            // If nothing is available, block to read only one character
172            if (__length < 1)
173                __length = 1;
174    
175    
176            if ((ch = __read()) == -1)
177                return -1;
178    
179            off = offset;
180    
181            do
182            {
183                buffer[offset++] = (byte)ch;
184            }
185            while (--__length > 0 && (ch = __read()) != -1);
186    
187    
188            return (offset - off);
189        }
190    
191    
192        // PushbackInputStream in JDK 1.1.3 returns the wrong thing
193        // TODO - can we delete this override now?
194        /***
195         * Returns the number of bytes that can be read without blocking EXCEPT
196         * when newline conversions have to be made somewhere within the
197         * available block of bytes.  In other words, you really should not
198         * rely on the value returned by this method if you are trying to avoid
199         * blocking.
200         ***/
201        @Override
202        public int available() throws IOException
203        {
204            if (in == null) {
205                throw new IOException("Stream closed");
206            }
207            return (buf.length - pos) + in.available();
208        }
209    
210    }