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 ***/
034
035 public final class ToNetASCIIInputStream extends FilterInputStream
036 {
037 private static final int __NOTHING_SPECIAL = 0;
038 private static final int __LAST_WAS_CR = 1;
039 private static final int __LAST_WAS_NL = 2;
040 private int __status;
041
042 /***
043 * Creates a ToNetASCIIInputStream instance that wraps an existing
044 * InputStream.
045 * <p>
046 * @param input The InputStream to .
047 ***/
048 public ToNetASCIIInputStream(InputStream input)
049 {
050 super(input);
051 __status = __NOTHING_SPECIAL;
052 }
053
054
055 /***
056 * Reads and returns the next byte in the stream. If the end of the
057 * message has been reached, returns -1.
058 * <p>
059 * @return The next character in the stream. Returns -1 if the end of the
060 * stream has been reached.
061 * @exception IOException If an error occurs while reading the underlying
062 * stream.
063 ***/
064 @Override
065 public int read() throws IOException
066 {
067 int ch;
068
069 if (__status == __LAST_WAS_NL)
070 {
071 __status = __NOTHING_SPECIAL;
072 return '\n';
073 }
074
075 ch = in.read();
076
077 switch (ch)
078 {
079 case '\r':
080 __status = __LAST_WAS_CR;
081 return '\r';
082 case '\n':
083 if (__status != __LAST_WAS_CR)
084 {
085 __status = __LAST_WAS_NL;
086 return '\r';
087 }
088 //$FALL-THROUGH$
089 default:
090 __status = __NOTHING_SPECIAL;
091 return ch;
092 }
093 // statement not reached
094 //return ch;
095 }
096
097
098 /***
099 * Reads the next number of bytes from the stream into an array and
100 * returns the number of bytes read. Returns -1 if the end of the
101 * stream has been reached.
102 * <p>
103 * @param buffer The byte array in which to store the data.
104 * @return The number of bytes read. Returns -1 if the
105 * end of the message has been reached.
106 * @exception IOException If an error occurs in reading the underlying
107 * stream.
108 ***/
109 @Override
110 public int read(byte buffer[]) throws IOException
111 {
112 return read(buffer, 0, buffer.length);
113 }
114
115
116 /***
117 * Reads the next number of bytes from the stream into an array and returns
118 * the number of bytes read. Returns -1 if the end of the
119 * message has been reached. The characters are stored in the array
120 * starting from the given offset and up to the length specified.
121 * <p>
122 * @param buffer The byte array in which to store the data.
123 * @param offset The offset into the array at which to start storing data.
124 * @param length The number of bytes to read.
125 * @return The number of bytes read. Returns -1 if the
126 * end of the stream has been reached.
127 * @exception IOException If an error occurs while reading the underlying
128 * stream.
129 ***/
130 @Override
131 public int read(byte buffer[], int offset, int length) throws IOException
132 {
133 int ch, off;
134
135 if (length < 1) {
136 return 0;
137 }
138
139 ch = available();
140
141 if (length > ch) {
142 length = ch;
143 }
144
145 // If nothing is available, block to read only one character
146 if (length < 1) {
147 length = 1;
148 }
149
150 if ((ch = read()) == -1) {
151 return -1;
152 }
153
154 off = offset;
155
156 do
157 {
158 buffer[offset++] = (byte)ch;
159 }
160 while (--length > 0 && (ch = read()) != -1);
161
162 return (offset - off);
163 }
164
165 /*** Returns false. Mark is not supported. ***/
166 @Override
167 public boolean markSupported()
168 {
169 return false;
170 }
171
172 @Override
173 public int available() throws IOException
174 {
175 int result;
176
177 result = in.available();
178
179 if (__status == __LAST_WAS_NL) {
180 return (result + 1);
181 }
182
183 return result;
184 }
185 }