35 * {@link com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl} is replaced |
37 * {@link com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl} is replaced |
36 * by {@link com.sun.org.apache.xml.internal.serializer.dom3.LSSerializerImpl}. |
38 * by {@link com.sun.org.apache.xml.internal.serializer.dom3.LSSerializerImpl}. |
37 */ |
39 */ |
38 public class EncodingInfo { |
40 public class EncodingInfo { |
39 |
41 |
40 // An array to hold the argument for a method of Charset, CharsetEncoder or CharToByteConverter. |
|
41 private Object [] fArgsForMethod = null; |
|
42 |
|
43 // name of encoding as registered with IANA; |
42 // name of encoding as registered with IANA; |
44 // preferably a MIME name, but aliases are fine too. |
43 // preferably a MIME name, but aliases are fine too. |
45 String ianaName; |
44 String ianaName; |
46 String javaName; |
45 String javaName; |
47 int lastPrintable; |
46 int lastPrintable; |
48 |
47 |
49 // The CharsetEncoder with which we test unusual characters. |
48 // The CharsetEncoder with which we test unusual characters. |
50 Object fCharsetEncoder = null; |
49 CharsetEncoder fCharsetEncoder = null; |
51 |
|
52 // The CharToByteConverter with which we test unusual characters. |
|
53 Object fCharToByteConverter = null; |
|
54 |
|
55 // Is the converter null because it can't be instantiated |
|
56 // for some reason (perhaps we're running with insufficient authority as |
|
57 // an applet? |
|
58 boolean fHaveTriedCToB = false; |
|
59 |
50 |
60 // Is the charset encoder usable or available. |
51 // Is the charset encoder usable or available. |
61 boolean fHaveTriedCharsetEncoder = false; |
52 boolean fHaveTriedCharsetEncoder = false; |
62 |
53 |
63 /** |
54 /** |
116 * @param ch a code point (0-0x10ffff) |
107 * @param ch a code point (0-0x10ffff) |
117 */ |
108 */ |
118 private boolean isPrintable0(char ch) { |
109 private boolean isPrintable0(char ch) { |
119 |
110 |
120 // Attempt to get a CharsetEncoder for this encoding. |
111 // Attempt to get a CharsetEncoder for this encoding. |
121 if (fCharsetEncoder == null && CharsetMethods.fgNIOCharsetAvailable && !fHaveTriedCharsetEncoder) { |
112 if (fCharsetEncoder == null && !fHaveTriedCharsetEncoder) { |
122 if (fArgsForMethod == null) { |
|
123 fArgsForMethod = new Object [1]; |
|
124 } |
|
125 // try and create the CharsetEncoder |
113 // try and create the CharsetEncoder |
126 try { |
114 try { |
127 fArgsForMethod[0] = javaName; |
115 Charset charset = java.nio.charset.Charset.forName(javaName); |
128 Object charset = CharsetMethods.fgCharsetForNameMethod.invoke(null, fArgsForMethod); |
116 if (charset.canEncode()) { |
129 if (((Boolean) CharsetMethods.fgCharsetCanEncodeMethod.invoke(charset, (Object[]) null)).booleanValue()) { |
117 fCharsetEncoder = charset.newEncoder(); |
130 fCharsetEncoder = CharsetMethods.fgCharsetNewEncoderMethod.invoke(charset, (Object[]) null); |
|
131 } |
118 } |
132 // This charset cannot be used for encoding, don't try it again... |
119 // This charset cannot be used for encoding, don't try it again... |
133 else { |
120 else { |
134 fHaveTriedCharsetEncoder = true; |
121 fHaveTriedCharsetEncoder = true; |
135 } |
122 } |
140 } |
127 } |
141 } |
128 } |
142 // Attempt to use the CharsetEncoder to determine whether the character is printable. |
129 // Attempt to use the CharsetEncoder to determine whether the character is printable. |
143 if (fCharsetEncoder != null) { |
130 if (fCharsetEncoder != null) { |
144 try { |
131 try { |
145 fArgsForMethod[0] = new Character(ch); |
132 return fCharsetEncoder.canEncode(ch); |
146 return ((Boolean) CharsetMethods.fgCharsetEncoderCanEncodeMethod.invoke(fCharsetEncoder, fArgsForMethod)).booleanValue(); |
|
147 } |
133 } |
148 catch (Exception e) { |
134 catch (Exception e) { |
149 // obviously can't use this charset encoder; possibly a JDK bug |
135 // obviously can't use this charset encoder; possibly a JDK bug |
150 fCharsetEncoder = null; |
136 fCharsetEncoder = null; |
151 fHaveTriedCharsetEncoder = false; |
137 fHaveTriedCharsetEncoder = false; |
152 } |
138 } |
153 } |
139 } |
154 |
140 |
155 // As a last resort try to use a sun.io.CharToByteConverter to |
141 return false; |
156 // determine whether this character is printable. We will always |
|
157 // reach here on JDK 1.3 or below. |
|
158 if (fCharToByteConverter == null) { |
|
159 if (fHaveTriedCToB || !CharToByteConverterMethods.fgConvertersAvailable) { |
|
160 // forget it; nothing we can do... |
|
161 return false; |
|
162 } |
|
163 if (fArgsForMethod == null) { |
|
164 fArgsForMethod = new Object [1]; |
|
165 } |
|
166 // try and create the CharToByteConverter |
|
167 try { |
|
168 fArgsForMethod[0] = javaName; |
|
169 fCharToByteConverter = CharToByteConverterMethods.fgGetConverterMethod.invoke(null, fArgsForMethod); |
|
170 } |
|
171 catch (Exception e) { |
|
172 // don't try it again... |
|
173 fHaveTriedCToB = true; |
|
174 return false; |
|
175 } |
|
176 } |
|
177 try { |
|
178 fArgsForMethod[0] = new Character(ch); |
|
179 return ((Boolean) CharToByteConverterMethods.fgCanConvertMethod.invoke(fCharToByteConverter, fArgsForMethod)).booleanValue(); |
|
180 } |
|
181 catch (Exception e) { |
|
182 // obviously can't use this converter; probably some kind of |
|
183 // security restriction |
|
184 fCharToByteConverter = null; |
|
185 fHaveTriedCToB = false; |
|
186 return false; |
|
187 } |
|
188 } |
142 } |
189 |
143 |
190 // is this an encoding name recognized by this JDK? |
144 // is this an encoding name recognized by this JDK? |
191 // if not, will throw UnsupportedEncodingException |
145 // if not, will throw UnsupportedEncodingException |
192 public static void testJavaEncodingName(String name) throws UnsupportedEncodingException { |
146 public static void testJavaEncodingName(String name) throws UnsupportedEncodingException { |
193 final byte [] bTest = {(byte)'v', (byte)'a', (byte)'l', (byte)'i', (byte)'d'}; |
147 final byte [] bTest = {(byte)'v', (byte)'a', (byte)'l', (byte)'i', (byte)'d'}; |
194 String s = new String(bTest, name); |
148 String s = new String(bTest, name); |
195 } |
149 } |
196 |
150 |
197 /** |
|
198 * Holder of methods from java.nio.charset.Charset and java.nio.charset.CharsetEncoder. |
|
199 */ |
|
200 static class CharsetMethods { |
|
201 |
|
202 // Method: java.nio.charset.Charset.forName(java.lang.String) |
|
203 private static java.lang.reflect.Method fgCharsetForNameMethod = null; |
|
204 |
|
205 // Method: java.nio.charset.Charset.canEncode() |
|
206 private static java.lang.reflect.Method fgCharsetCanEncodeMethod = null; |
|
207 |
|
208 // Method: java.nio.charset.Charset.newEncoder() |
|
209 private static java.lang.reflect.Method fgCharsetNewEncoderMethod = null; |
|
210 |
|
211 // Method: java.nio.charset.CharsetEncoder.canEncode(char) |
|
212 private static java.lang.reflect.Method fgCharsetEncoderCanEncodeMethod = null; |
|
213 |
|
214 // Flag indicating whether or not java.nio.charset.* is available. |
|
215 private static boolean fgNIOCharsetAvailable = false; |
|
216 |
|
217 private CharsetMethods() {} |
|
218 |
|
219 // Attempt to get methods for Charset and CharsetEncoder on class initialization. |
|
220 static { |
|
221 try { |
|
222 Class charsetClass = Class.forName("java.nio.charset.Charset"); |
|
223 Class charsetEncoderClass = Class.forName("java.nio.charset.CharsetEncoder"); |
|
224 fgCharsetForNameMethod = charsetClass.getMethod("forName", new Class [] {String.class}); |
|
225 fgCharsetCanEncodeMethod = charsetClass.getMethod("canEncode", new Class [] {}); |
|
226 fgCharsetNewEncoderMethod = charsetClass.getMethod("newEncoder", new Class [] {}); |
|
227 fgCharsetEncoderCanEncodeMethod = charsetEncoderClass.getMethod("canEncode", new Class [] {Character.TYPE}); |
|
228 fgNIOCharsetAvailable = true; |
|
229 } |
|
230 // ClassNotFoundException, NoSuchMethodException or SecurityException |
|
231 // Whatever the case, we cannot use java.nio.charset.*. |
|
232 catch (Exception exc) { |
|
233 fgCharsetForNameMethod = null; |
|
234 fgCharsetCanEncodeMethod = null; |
|
235 fgCharsetEncoderCanEncodeMethod = null; |
|
236 fgCharsetNewEncoderMethod = null; |
|
237 fgNIOCharsetAvailable = false; |
|
238 } |
|
239 } |
|
240 } |
|
241 |
|
242 /** |
|
243 * Holder of methods from sun.io.CharToByteConverter. |
|
244 */ |
|
245 static class CharToByteConverterMethods { |
|
246 |
|
247 // Method: sun.io.CharToByteConverter.getConverter(java.lang.String) |
|
248 private static java.lang.reflect.Method fgGetConverterMethod = null; |
|
249 |
|
250 // Method: sun.io.CharToByteConverter.canConvert(char) |
|
251 private static java.lang.reflect.Method fgCanConvertMethod = null; |
|
252 |
|
253 // Flag indicating whether or not sun.io.CharToByteConverter is available. |
|
254 private static boolean fgConvertersAvailable = false; |
|
255 |
|
256 private CharToByteConverterMethods() {} |
|
257 |
|
258 // Attempt to get methods for char to byte converter on class initialization. |
|
259 static { |
|
260 try { |
|
261 Class clazz = Class.forName("sun.io.CharToByteConverter"); |
|
262 fgGetConverterMethod = clazz.getMethod("getConverter", new Class [] {String.class}); |
|
263 fgCanConvertMethod = clazz.getMethod("canConvert", new Class [] {Character.TYPE}); |
|
264 fgConvertersAvailable = true; |
|
265 } |
|
266 // ClassNotFoundException, NoSuchMethodException or SecurityException |
|
267 // Whatever the case, we cannot use sun.io.CharToByteConverter. |
|
268 catch (Exception exc) { |
|
269 fgGetConverterMethod = null; |
|
270 fgCanConvertMethod = null; |
|
271 fgConvertersAvailable = false; |
|
272 } |
|
273 } |
|
274 } |
|
275 } |
151 } |