View Javadoc

    1   /*
    2    * Copyright 2001-2005 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.net.io;
    17
    18  import java.io.IOException;
    19  import java.io.InputStream;
    20  import java.io.PushbackInputStream;
    21
    22  /****
    23   * This class wraps an input stream, replacing all occurrences
    24   * of &lt;CR&gt;&lt;LF&gt; (carriage return followed by a linefeed),
    25   * which is the NETASCII standard for representing a newline, with the
    26   * local line separator representation.  You would use this class to
    27   * implement ASCII file transfers requiring conversion from NETASCII.
    28   * <p>
    29   * <p>
    30   * @author Daniel F. Savarese
    31   ***/
    32
    33  public final class FromNetASCIIInputStream extends PushbackInputStream
    34  {
    35      static final boolean _noConversionRequired;
    36      static final String _lineSeparator;
    37      static final byte[] _lineSeparatorBytes;
    38
    39      static {
    40          _lineSeparator = System.getProperty("line.separator");
    41          _noConversionRequired = _lineSeparator.equals("\r\n");
    42          _lineSeparatorBytes = _lineSeparator.getBytes();
    43      }
    44
    45      private int __length = 0;
    46
    47      /****
    48       * Returns true if the NetASCII line separator differs from the system
    49       * line separator, false if they are the same.  This method is useful
    50       * to determine whether or not you need to instantiate a
    51       * FromNetASCIIInputStream object.
    52       * <p>
    53       * @return True if the NETASCII line separator differs from the local
    54       *   system line separator, false if they are the same.
    55       ***/
    56      public static final boolean isConversionRequired()
    57      {
    58          return !_noConversionRequired;
    59      }
    60
    61      /****
    62       * Creates a FromNetASCIIInputStream instance that wraps an existing
    63       * InputStream.
    64       ***/
    65      public FromNetASCIIInputStream(InputStream input)
    66      {
    67          super(input, _lineSeparatorBytes.length + 1);
    68      }
    69
    70
    71      private int __read() throws IOException
    72      {
    73          int ch;
    74
    75          ch = super.read();
    76
    77          if (ch == '\r')
    78          {
    79              ch = super.read();
    80              if (ch == '\n')
    81              {
    82                  unread(_lineSeparatorBytes);
    83                  ch = super.read();
    84                  // This is a kluge for read(byte[], ...) to read the right amount
    85                  --__length;
    86              }
    87              else
    88              {
    89                  if (ch != -1)
    90                      unread(ch);
    91                  return '\r';
    92              }
    93          }
    94
    95          return ch;
    96      }
    97
    98
    99      /****
    100      * Reads and returns the next byte in the stream.  If the end of the
    101      * message has been reached, returns -1.  Note that a call to this method
    102      * may result in multiple reads from the underlying input stream in order
    103      * to convert NETASCII line separators to the local line separator format.
    104      * This is transparent to the programmer and is only mentioned for
    105      * completeness.
    106      * <p>
    107      * @return The next character in the stream. Returns -1 if the end of the
    108      *          stream has been reached.
    109      * @exception IOException If an error occurs while reading the underlying
    110      *            stream.
    111      ***/
    112     public int read() throws IOException
    113     {
    114         if (_noConversionRequired)
    115             return super.read();
    116
    117         return __read();
    118     }
    119
    120
    121     /****
    122      * Reads the next number of bytes from the stream into an array and
    123      * returns the number of bytes read.  Returns -1 if the end of the
    124      * stream has been reached.
    125      * <p>
    126      * @param buffer  The byte array in which to store the data.
    127      * @return The number of bytes read. Returns -1 if the
    128      *          end of the message has been reached.
    129      * @exception IOException If an error occurs in reading the underlying
    130      *            stream.
    131      ***/
    132     public int read(byte buffer[]) throws IOException
    133     {
    134         return read(buffer, 0, buffer.length);
    135     }
    136
    137
    138     /****
    139      * Reads the next number of bytes from the stream into an array and returns
    140      * the number of bytes read.  Returns -1 if the end of the
    141      * message has been reached.  The characters are stored in the array
    142      * starting from the given offset and up to the length specified.
    143      * <p>
    144      * @param buffer The byte array in which to store the data.
    145      * @param offset  The offset into the array at which to start storing data.
    146      * @param length   The number of bytes to read.
    147      * @return The number of bytes read. Returns -1 if the
    148      *          end of the stream has been reached.
    149      * @exception IOException If an error occurs while reading the underlying
    150      *            stream.
    151      ***/
    152     public int read(byte buffer[], int offset, int length) throws IOException
    153     {
    154         int ch, off;
    155
    156         if (length < 1)
    157             return 0;
    158
    159         ch = available();
    160
    161         __length = (length > ch ? ch : length);
    162
    163         // If nothing is available, block to read only one character
    164         if (__length < 1)
    165             __length = 1;
    166
    167         if (_noConversionRequired)
    168             return super.read(buffer, offset, __length);
    169
    170         if ((ch = __read()) == -1)
    171             return -1;
    172
    173         off = offset;
    174
    175         do
    176         {
    177             buffer[offset++] = (byte)ch;
    178         }
    179         while (--__length > 0 && (ch = __read()) != -1);
    180
    181
    182         return (offset - off);
    183     }
    184
    185
    186     // PushbackInputStream in JDK 1.1.3 returns the wrong thing
    187     /****
    188      * Returns the number of bytes that can be read without blocking EXCEPT
    189      * when newline conversions have to be made somewhere within the
    190      * available block of bytes.  In other words, you really should not
    191      * rely on the value returned by this method if you are trying to avoid
    192      * blocking.
    193      ***/
    194     public int available() throws IOException
    195     {
    196         return (buf.length - pos) + in.available();
    197     }
    198
    199 }