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