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