1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
package org.ini4j.spi; |
17 | |
|
18 | |
import java.io.IOException; |
19 | |
import java.io.InputStream; |
20 | |
import java.io.InputStreamReader; |
21 | |
import java.io.PushbackInputStream; |
22 | |
import java.io.Reader; |
23 | |
|
24 | |
import java.nio.charset.Charset; |
25 | |
|
26 | |
class UnicodeInputStreamReader extends Reader |
27 | |
{ |
28 | |
private static final int BOM_SIZE = 4; |
29 | |
|
30 | 129 | private static enum Bom |
31 | |
{ |
32 | 1 | UTF32BE("UTF-32BE", new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0xFE, (byte) 0xFF }), |
33 | 1 | UTF32LE("UTF-32LE", new byte[] { (byte) 0xFF, (byte) 0xFE, (byte) 0x00, (byte) 0x00 }), |
34 | 1 | UTF16BE("UTF-16BE", new byte[] { (byte) 0xFE, (byte) 0xFF }), |
35 | 1 | UTF16LE("UTF-16LE", new byte[] { (byte) 0xFF, (byte) 0xFE }), |
36 | 1 | UTF8("UTF-8", new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF }); |
37 | |
private final byte[] _bytes; |
38 | |
private Charset _charset; |
39 | |
|
40 | |
@SuppressWarnings("PMD.ArrayIsStoredDirectly") |
41 | |
private Bom(String charsetName, byte[] bytes) |
42 | 5 | { |
43 | |
try |
44 | |
{ |
45 | 5 | _charset = Charset.forName(charsetName); |
46 | |
} |
47 | 0 | catch (Exception x) |
48 | |
{ |
49 | 0 | _charset = null; |
50 | 5 | } |
51 | |
|
52 | 5 | _bytes = bytes; |
53 | 5 | } |
54 | |
|
55 | |
private static Bom find(byte[] data) |
56 | |
{ |
57 | 55 | Bom ret = null; |
58 | |
|
59 | 312 | for (Bom bom : values()) |
60 | |
{ |
61 | 266 | if (bom.supported() && bom.match(data)) |
62 | |
{ |
63 | 9 | ret = bom; |
64 | |
|
65 | 9 | break; |
66 | |
} |
67 | |
} |
68 | |
|
69 | 55 | return ret; |
70 | |
} |
71 | |
|
72 | |
private boolean match(byte[] data) |
73 | |
{ |
74 | 266 | boolean ok = true; |
75 | |
|
76 | 294 | for (int i = 0; i < _bytes.length; i++) |
77 | |
{ |
78 | 285 | if (data[i] != _bytes[i]) |
79 | |
{ |
80 | 257 | ok = false; |
81 | |
|
82 | 257 | break; |
83 | |
} |
84 | |
} |
85 | |
|
86 | 266 | return ok; |
87 | |
} |
88 | |
|
89 | |
private boolean supported() |
90 | |
{ |
91 | 266 | return _charset != null; |
92 | |
} |
93 | |
} |
94 | |
|
95 | |
private final Charset _defaultEncoding; |
96 | |
private InputStreamReader _reader; |
97 | |
private final PushbackInputStream _stream; |
98 | |
|
99 | |
UnicodeInputStreamReader(InputStream in, Charset defaultEnc) |
100 | 55 | { |
101 | 55 | _stream = new PushbackInputStream(in, BOM_SIZE); |
102 | 55 | _defaultEncoding = defaultEnc; |
103 | 55 | } |
104 | |
|
105 | |
public void close() throws IOException |
106 | |
{ |
107 | 43 | init(); |
108 | 43 | _reader.close(); |
109 | 43 | } |
110 | |
|
111 | |
public int read(char[] cbuf, int off, int len) throws IOException |
112 | |
{ |
113 | 100 | init(); |
114 | |
|
115 | 100 | return _reader.read(cbuf, off, len); |
116 | |
} |
117 | |
|
118 | |
|
119 | |
|
120 | |
|
121 | |
|
122 | |
protected void init() throws IOException |
123 | |
{ |
124 | 143 | if (_reader != null) |
125 | |
{ |
126 | 88 | return; |
127 | |
} |
128 | |
|
129 | |
Charset encoding; |
130 | 55 | byte[] data = new byte[BOM_SIZE]; |
131 | |
int n; |
132 | |
int unread; |
133 | |
|
134 | 55 | n = _stream.read(data, 0, data.length); |
135 | 55 | Bom bom = Bom.find(data); |
136 | |
|
137 | 55 | if (bom == null) |
138 | |
{ |
139 | 46 | encoding = _defaultEncoding; |
140 | 46 | unread = n; |
141 | |
} |
142 | |
else |
143 | |
{ |
144 | 9 | encoding = bom._charset; |
145 | 9 | unread = data.length - bom._bytes.length; |
146 | |
} |
147 | |
|
148 | 55 | if (unread > 0) |
149 | |
{ |
150 | 55 | _stream.unread(data, (n - unread), unread); |
151 | |
} |
152 | |
|
153 | 55 | _reader = new InputStreamReader(_stream, encoding); |
154 | 55 | } |
155 | |
} |