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 * <LF> (linefeed) characters with <CR><LF> (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 // else 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 }