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 ***/
34
35 public final class ToNetASCIIInputStream extends FilterInputStream
36 {
37 private static final int __NOTHING_SPECIAL = 0;
38 private static final int __LAST_WAS_CR = 1;
39 private static final int __LAST_WAS_NL = 2;
40 private int __status;
41
42 /***
43 * Creates a ToNetASCIIInputStream instance that wraps an existing
44 * InputStream.
45 * <p>
46 * @param input The InputStream to wrap.
47 ***/
48 public ToNetASCIIInputStream(InputStream input)
49 {
50 super(input);
51 __status = __NOTHING_SPECIAL;
52 }
53
54
55 /***
56 * Reads and returns the next byte in the stream. If the end of the
57 * message has been reached, returns -1.
58 * <p>
59 * @return The next character in the stream. Returns -1 if the end of the
60 * stream has been reached.
61 * @exception IOException If an error occurs while reading the underlying
62 * stream.
63 ***/
64 @Override
65 public int read() throws IOException
66 {
67 int ch;
68
69 if (__status == __LAST_WAS_NL)
70 {
71 __status = __NOTHING_SPECIAL;
72 return '\n';
73 }
74
75 ch = in.read();
76
77 switch (ch)
78 {
79 case '\r':
80 __status = __LAST_WAS_CR;
81 return '\r';
82 case '\n':
83 if (__status != __LAST_WAS_CR)
84 {
85 __status = __LAST_WAS_NL;
86 return '\r';
87 }
88 //$FALL-THROUGH$
89 default:
90 __status = __NOTHING_SPECIAL;
91 return ch;
92 }
93 // statement not reached
94 //return ch;
95 }
96
97
98 /***
99 * 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 }