    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                    return '\r';
    093                }
    094            }
    095
    096            return ch;
    097        }
    098
    099
    100        /***
    101         * Reads and returns the next byte in the stream.  If the end of the
    102         * message has been reached, returns -1.  Note that a call to this method
    103         * may result in multiple reads from the underlying input stream in order
    104         * to convert NETASCII line separators to the local line separator format.
    105         * This is transparent to the programmer and is only mentioned for
    106         * completeness.
    107         * <p>
    108         * @return The next character in the stream. Returns -1 if the end of the
    109         *          stream has been reached.
    110         * @exception IOException If an error occurs while reading the underlying
    111         *            stream.
    112         ***/
    113        @Override
    114        public int read() throws IOException
    115        {
    116            if (_noConversionRequired)
    117                return super.read();
    118
    119            return __read();
    120        }
    121
    122
    123        /***
    124         * Reads the next number of bytes from the stream into an array and
    125         * returns the number of bytes read.  Returns -1 if the end of the
    126         * stream has been reached.
    127         * <p>
    128         * @param buffer  The byte array in which to store the data.
    129         * @return The number of bytes read. Returns -1 if the
    130         *          end of the message has been reached.
    131         * @exception IOException If an error occurs in reading the underlying
    132         *            stream.
    133         ***/
    134        @Override
    135        public int read(byte buffer[]) throws IOException
    136        {
    137            return read(buffer, 0, buffer.length);
    138        }
    139
    140
    141        /***
    142         * Reads the next number of bytes from the stream into an array and returns
    143         * the number of bytes read.  Returns -1 if the end of the
    144         * message has been reached.  The characters are stored in the array
    145         * starting from the given offset and up to the length specified.
    146         * <p>
    147         * @param buffer The byte array in which to store the data.
    148         * @param offset  The offset into the array at which to start storing data.
    149         * @param length   The number of bytes to read.
    150         * @return The number of bytes read. Returns -1 if the
    151         *          end of the stream has been reached.
    152         * @exception IOException If an error occurs while reading the underlying
    153         *            stream.
    154         ***/
    155        @Override
    156        public int read(byte buffer[], int offset, int length) throws IOException
    157        {
    158            if (_noConversionRequired)
    159                return super.read(buffer, offset, length);
    160
    161            if (length < 1)
    162                return 0;
    163
    164            int ch, off;
    165
    166            ch = available();
    167
    168            __length = (length > ch ? ch : length);
    169
    170            // If nothing is available, block to read only one character
    171            if (__length < 1)
    172                __length = 1;
    173
    174
    175            if ((ch = __read()) == -1)
    176                return -1;
    177
    178            off = offset;
    179
    180            do
    181            {
    182                buffer[offset++] = (byte)ch;
    183            }
    184            while (--__length > 0 && (ch = __read()) != -1);
    185
    186
    187            return (offset - off);
    188        }
    189
    190
    191        // PushbackInputStream in JDK 1.1.3 returns the wrong thing
    192        // TODO - can we delete this override now?
    193        /***
    194         * Returns the number of bytes that can be read without blocking EXCEPT
    195         * when newline conversions have to be made somewhere within the
    196         * available block of bytes.  In other words, you really should not
    197         * rely on the value returned by this method if you are trying to avoid
    198         * blocking.
    199         ***/
    200        @Override
    201        public int available() throws IOException
    202        {
    203            if (in == null) {
    204                throw new IOException("Stream closed");
    205            }
    206            return (buf.length - pos) + in.available();
    207        }
    208
    209    }