001 /*
002 * Copyright 2001-2005 The Apache Software Foundation
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.apache.commons.net.io;
017
018 import java.io.IOException;
019 import java.io.InputStream;
020 import java.io.PushbackInputStream;
021
022 /***
023 * This class wraps an input stream, replacing all occurrences
024 * of <CR><LF> (carriage return followed by a linefeed),
025 * which is the NETASCII standard for representing a newline, with the
026 * local line separator representation. You would use this class to
027 * implement ASCII file transfers requiring conversion from NETASCII.
028 * <p>
029 * <p>
030 * @author Daniel F. Savarese
031 ***/
032
033 public final class FromNetASCIIInputStream extends PushbackInputStream
034 {
035 static final boolean _noConversionRequired;
036 static final String _lineSeparator;
037 static final byte[] _lineSeparatorBytes;
038
039 static {
040 _lineSeparator = System.getProperty("line.separator");
041 _noConversionRequired = _lineSeparator.equals("\r\n");
042 _lineSeparatorBytes = _lineSeparator.getBytes();
043 }
044
045 private int __length = 0;
046
047 /***
048 * Returns true if the NetASCII line separator differs from the system
049 * line separator, false if they are the same. This method is useful
050 * to determine whether or not you need to instantiate a
051 * FromNetASCIIInputStream object.
052 * <p>
053 * @return True if the NETASCII line separator differs from the local
054 * system line separator, false if they are the same.
055 ***/
056 public static final boolean isConversionRequired()
057 {
058 return !_noConversionRequired;
059 }
060
061 /***
062 * Creates a FromNetASCIIInputStream instance that wraps an existing
063 * InputStream.
064 ***/
065 public FromNetASCIIInputStream(InputStream input)
066 {
067 super(input, _lineSeparatorBytes.length + 1);
068 }
069
070
071 private int __read() throws IOException
072 {
073 int ch;
074
075 ch = super.read();
076
077 if (ch == '\r')
078 {
079 ch = super.read();
080 if (ch == '\n')
081 {
082 unread(_lineSeparatorBytes);
083 ch = super.read();
084 // This is a kluge for read(byte[], ...) to read the right amount
085 --__length;
086 }
087 else
088 {
089 if (ch != -1)
090 unread(ch);
091 return '\r';
092 }
093 }
094
095 return ch;
096 }
097
098
099 /***
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 }