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