1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net.io;
19
20 import java.io.FilterInputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23
24 /***
25 * This class wraps an input stream, replacing all singly occurring
26 * <LF> (linefeed) characters with <CR><LF> (carriage return
27 * followed by linefeed), which is the NETASCII standard for representing
28 * a newline.
29 * You would use this class to implement ASCII file transfers requiring
30 * conversion to NETASCII.
31 * <p>
32 * <p>
33 * @author Daniel F. Savarese
34 ***/
35
36 public final class ToNetASCIIInputStream extends FilterInputStream
37 {
38 private static final int __NOTHING_SPECIAL = 0;
39 private static final int __LAST_WAS_CR = 1;
40 private static final int __LAST_WAS_NL = 2;
41 private int __status;
42
43 /***
44 * Creates a ToNetASCIIInputStream instance that wraps an existing
45 * InputStream.
46 * <p>
47 * @param input The InputStream to .
48 ***/
49 public ToNetASCIIInputStream(InputStream input)
50 {
51 super(input);
52 __status = __NOTHING_SPECIAL;
53 }
54
55
56 /***
57 * Reads and returns the next byte in the stream. If the end of the
58 * message has been reached, returns -1.
59 * <p>
60 * @return The next character in the stream. Returns -1 if the end of the
61 * stream has been reached.
62 * @exception IOException If an error occurs while reading the underlying
63 * stream.
64 ***/
65 @Override
66 public int read() throws IOException
67 {
68 int ch;
69
70 if (__status == __LAST_WAS_NL)
71 {
72 __status = __NOTHING_SPECIAL;
73 return '\n';
74 }
75
76 ch = in.read();
77
78 switch (ch)
79 {
80 case '\r':
81 __status = __LAST_WAS_CR;
82 return '\r';
83 case '\n':
84 if (__status != __LAST_WAS_CR)
85 {
86 __status = __LAST_WAS_NL;
87 return '\r';
88 }
89 // else fall through
90 default:
91 __status = __NOTHING_SPECIAL;
92 return ch;
93 }
94 // statement not reached
95 //return ch;
96 }
97
98
99 /***
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 }