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 <CR><LF> (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 }