    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     * @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    }