1 /*
2
3 Licensed to the Apache Software Foundation (ASF) under one or more
4 contributor license agreements. See the NOTICE file distributed with
5 this work for additional information regarding copyright ownership.
6 The ASF licenses this file to You under the Apache License, Version 2.0
7 (the "License"); you may not use this file except in compliance with
8 the License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17
18 */
19 package org.apache.batik.util.io;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.Reader;
24 import java.util.HashMap;
25 import java.util.Map;
26
27 import org.apache.batik.util.EncodingUtilities;
28
29 /**
30 * This class represents a NormalizingReader which handles streams of
31 * bytes.
32 *
33 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
34 * @version $Id: StreamNormalizingReader.java 1733416 2016-03-03 07:07:13Z gadams $
35 */
36 public class StreamNormalizingReader extends NormalizingReader {
37
38 /**
39 * The char decoder.
40 */
41 protected CharDecoder charDecoder;
42
43 /**
44 * The next char.
45 */
46 protected int nextChar = -1;
47
48 /**
49 * The current line in the stream.
50 */
51 protected int line = 1;
52
53 /**
54 * The current column in the stream.
55 */
56 protected int column;
57
58 /**
59 * Creates a new NormalizingReader. The encoding is assumed to be
60 * ISO-8859-1.
61 * @param is The input stream to decode.
62 */
63 public StreamNormalizingReader(InputStream is) throws IOException {
64 this(is, null);
65 }
66
67 /**
68 * Creates a new NormalizingReader.
69 * @param is The input stream to decode.
70 * @param enc The standard encoding name. A null encoding means
71 * ISO-8859-1.
72 */
73 public StreamNormalizingReader(InputStream is, String enc)
74 throws IOException {
75 if (enc == null) {
76 enc = "ISO-8859-1";
77 }
78 charDecoder = createCharDecoder(is, enc);
79 }
80
81 /**
82 * Creates a new NormalizingReader.
83 * @param r The reader to wrap.
84 */
85 public StreamNormalizingReader(Reader r) throws IOException {
86 charDecoder = new GenericDecoder(r);
87 }
88
89 /**
90 * This constructor is intended for use by subclasses.
91 */
92 protected StreamNormalizingReader() {
93 }
94
95 /**
96 * Read a single character. This method will block until a
97 * character is available, an I/O error occurs, or the end of the
98 * stream is reached.
99 */
100 public int read() throws IOException {
101 int result = nextChar;
102 if (result != -1) {
103 nextChar = -1;
104 if (result == 13) {
105 column = 0;
106 line++;
107 } else {
108 column++;
109 }
110 return result;
111 }
112 result = charDecoder.readChar();
113 switch (result) {
114 case 13:
115 column = 0;
116 line++;
117 int c = charDecoder.readChar();
118 if (c == 10) {
119 return 10;
120 }
121 nextChar = c;
122 return 10;
123
124 case 10:
125 column = 0;
126 line++;
127 }
128 return result;
129 }
130
131 /**
132 * Returns the current line in the stream.
133 */
134 public int getLine() {
135 return line;
136 }
137
138 /**
139 * Returns the current column in the stream.
140 */
141 public int getColumn() {
142 return column;
143 }
144
145 /**
146 * Close the stream.
147 */
148 public void close() throws IOException {
149 charDecoder.dispose();
150 charDecoder = null;
151 }
152
153 /**
154 * Creates the CharDecoder mapped with the given encoding name.
155 */
156 protected CharDecoder createCharDecoder(InputStream is, String enc)
157 throws IOException {
158 CharDecoderFactory cdf =
159 (CharDecoderFactory)charDecoderFactories.get(enc.toUpperCase());
160 if (cdf != null) {
161 return cdf.createCharDecoder(is);
162 }
163 String e = EncodingUtilities.javaEncoding(enc);
164 if (e == null) {
165 e = enc;
166 }
167 return new GenericDecoder(is, e);
168 }
169
170 /**
171 * The CharDecoder factories map.
172 */
173 protected static final Map charDecoderFactories = new HashMap(11);
174 static {
175 CharDecoderFactory cdf = new ASCIIDecoderFactory();
176 charDecoderFactories.put("ASCII", cdf);
177 charDecoderFactories.put("US-ASCII", cdf);
178 charDecoderFactories.put("ISO-8859-1", new ISO_8859_1DecoderFactory());
179 charDecoderFactories.put("UTF-8", new UTF8DecoderFactory());
180 charDecoderFactories.put("UTF-16", new UTF16DecoderFactory());
181 }
182
183 /**
184 * Represents a CharDecoder factory.
185 */
186 protected interface CharDecoderFactory {
187 CharDecoder createCharDecoder(InputStream is) throws IOException;
188 }
189
190 /**
191 * To create an ASCIIDecoder.
192 */
193 protected static class ASCIIDecoderFactory
194 implements CharDecoderFactory {
195 public CharDecoder createCharDecoder(InputStream is)
196 throws IOException {
197 return new ASCIIDecoder(is);
198 }
199 }
200
201 /**
202 * To create an ISO_8859_1Decoder.
203 */
204 protected static class ISO_8859_1DecoderFactory
205 implements CharDecoderFactory {
206 public CharDecoder createCharDecoder(InputStream is)
207 throws IOException {
208 return new ISO_8859_1Decoder(is);
209 }
210 }
211
212 /**
213 * To create a UTF8Decoder.
214 */
215 protected static class UTF8DecoderFactory
216 implements CharDecoderFactory {
217 public CharDecoder createCharDecoder(InputStream is)
218 throws IOException {
219 return new UTF8Decoder(is);
220 }
221 }
222
223 /**
224 * To create a UTF16Decoder.
225 */
226 protected static class UTF16DecoderFactory
227 implements CharDecoderFactory {
228 public CharDecoder createCharDecoder(InputStream is)
229 throws IOException {
230 return new UTF16Decoder(is);
231 }
232 }
233 }
234