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: static final boolean _noConversionRequired;
035: static final String _lineSeparator;
036: static final byte[] _lineSeparatorBytes;
037:
038: static {
039: _lineSeparator = System.getProperty("line.separator");
040: _noConversionRequired = _lineSeparator.equals("\r\n");
041: _lineSeparatorBytes = _lineSeparator.getBytes();
042: }
043:
044: private int __length = 0;
045:
046: /***
047: * Returns true if the NetASCII line separator differs from the system
048: * line separator, false if they are the same. This method is useful
049: * to determine whether or not you need to instantiate a
050: * FromNetASCIIInputStream object.
051: * <p>
052: * @return True if the NETASCII line separator differs from the local
053: * system line separator, false if they are the same.
054: ***/
055: public static final boolean isConversionRequired() {
056: return !_noConversionRequired;
057: }
058:
059: /***
060: * Creates a FromNetASCIIInputStream instance that wraps an existing
061: * InputStream.
062: ***/
063: public FromNetASCIIInputStream(InputStream input) {
064: super (input, _lineSeparatorBytes.length + 1);
065: }
066:
067: private int __read() throws IOException {
068: int ch;
069:
070: ch = super .read();
071:
072: if (ch == '\r') {
073: ch = super .read();
074: if (ch == '\n') {
075: unread(_lineSeparatorBytes);
076: ch = super .read();
077: // This is a kluge for read(byte[], ...) to read the right amount
078: --__length;
079: } else {
080: if (ch != -1)
081: unread(ch);
082: return '\r';
083: }
084: }
085:
086: return ch;
087: }
088:
089: /***
090: * Reads and returns the next byte in the stream. If the end of the
091: * message has been reached, returns -1. Note that a call to this method
092: * may result in multiple reads from the underlying input stream in order
093: * to convert NETASCII line separators to the local line separator format.
094: * This is transparent to the programmer and is only mentioned for
095: * completeness.
096: * <p>
097: * @return The next character in the stream. Returns -1 if the end of the
098: * stream has been reached.
099: * @exception IOException If an error occurs while reading the underlying
100: * stream.
101: ***/
102: public int read() throws IOException {
103: if (_noConversionRequired)
104: return super .read();
105:
106: return __read();
107: }
108:
109: /***
110: * Reads the next number of bytes from the stream into an array and
111: * returns the number of bytes read. Returns -1 if the end of the
112: * stream has been reached.
113: * <p>
114: * @param buffer The byte array in which to store the data.
115: * @return The number of bytes read. Returns -1 if the
116: * end of the message has been reached.
117: * @exception IOException If an error occurs in reading the underlying
118: * stream.
119: ***/
120: public int read(byte buffer[]) throws IOException {
121: return read(buffer, 0, buffer.length);
122: }
123:
124: /***
125: * Reads the next number of bytes from the stream into an array and returns
126: * the number of bytes read. Returns -1 if the end of the
127: * message has been reached. The characters are stored in the array
128: * starting from the given offset and up to the length specified.
129: * <p>
130: * @param buffer The byte array in which to store the data.
131: * @param offset The offset into the array at which to start storing data.
132: * @param length The number of bytes to read.
133: * @return The number of bytes read. Returns -1 if the
134: * end of the stream has been reached.
135: * @exception IOException If an error occurs while reading the underlying
136: * stream.
137: ***/
138: public int read(byte buffer[], int offset, int length)
139: throws IOException {
140: int ch, off;
141:
142: if (length < 1)
143: return 0;
144:
145: ch = available();
146:
147: __length = (length > ch ? ch : length);
148:
149: // If nothing is available, block to read only one character
150: if (__length < 1)
151: __length = 1;
152:
153: if (_noConversionRequired)
154: return super .read(buffer, offset, __length);
155:
156: if ((ch = __read()) == -1)
157: return -1;
158:
159: off = offset;
160:
161: do {
162: buffer[offset++] = (byte) ch;
163: } while (--__length > 0 && (ch = __read()) != -1);
164:
165: return (offset - off);
166: }
167:
168: // PushbackInputStream in JDK 1.1.3 returns the wrong thing
169: /***
170: * Returns the number of bytes that can be read without blocking EXCEPT
171: * when newline conversions have to be made somewhere within the
172: * available block of bytes. In other words, you really should not
173: * rely on the value returned by this method if you are trying to avoid
174: * blocking.
175: ***/
176: public int available() throws IOException {
177: return (buf.length - pos) + in.available();
178: }
179:
180: }
|