1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44:
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60:
61:
65: public abstract class Charset implements Comparable
66: {
67: private CharsetEncoder cachedEncoder;
68: private CharsetDecoder cachedDecoder;
69:
70:
73: private static CharsetProvider[] providers;
74:
75: private final String canonicalName;
76: private final String[] aliases;
77:
78: protected Charset (String canonicalName, String[] aliases)
79: {
80: checkName (canonicalName);
81: if (aliases != null)
82: {
83: int n = aliases.length;
84: for (int i = 0; i < n; ++i)
85: checkName (aliases[i]);
86: }
87:
88: cachedEncoder = null;
89: cachedDecoder = null;
90: this.canonicalName = canonicalName;
91: this.aliases = aliases;
92: }
93:
94:
97: private static void checkName (String name)
98: {
99: int n = name.length ();
100:
101: if (n == 0)
102: throw new IllegalCharsetNameException (name);
103:
104: char ch = name.charAt (0);
105: if (!(('A' <= ch && ch <= 'Z')
106: || ('a' <= ch && ch <= 'z')
107: || ('0' <= ch && ch <= '9')))
108: throw new IllegalCharsetNameException (name);
109:
110: for (int i = 1; i < n; ++i)
111: {
112: ch = name.charAt (i);
113: if (!(('A' <= ch && ch <= 'Z')
114: || ('a' <= ch && ch <= 'z')
115: || ('0' <= ch && ch <= '9')
116: || ch == '-' || ch == '.' || ch == ':' || ch == '_'))
117: throw new IllegalCharsetNameException (name);
118: }
119: }
120:
121:
129: public static Charset defaultCharset()
130: {
131: String encoding;
132:
133: try
134: {
135: encoding = SystemProperties.getProperty("file.encoding");
136: }
137: catch(SecurityException e)
138: {
139:
140: encoding = "ISO-8859-1";
141: }
142: catch(IllegalArgumentException e)
143: {
144:
145: encoding = "ISO-8859-1";
146: }
147:
148: try
149: {
150: return forName(encoding);
151: }
152: catch(UnsupportedCharsetException e)
153: {
154:
155: }
156: catch(IllegalCharsetNameException e)
157: {
158:
159: }
160: catch(IllegalArgumentException e)
161: {
162:
163: }
164:
165: throw new IllegalStateException("Can't get default charset!");
166: }
167:
168: public static boolean isSupported (String charsetName)
169: {
170: return charsetForName (charsetName) != null;
171: }
172:
173:
184: public static Charset forName (String charsetName)
185: {
186:
187: if(charsetName == null)
188: throw new IllegalArgumentException("Charset name must not be null.");
189:
190: Charset cs = charsetForName (charsetName);
191: if (cs == null)
192: throw new UnsupportedCharsetException (charsetName);
193: return cs;
194: }
195:
196:
204: private static Charset charsetForName(String charsetName)
205: {
206: checkName (charsetName);
207:
208:
209:
210: Charset cs = provider().charsetForName(charsetName);
211: if (cs == null)
212: {
213: CharsetProvider[] providers = providers2();
214: for (int i = 0; i < providers.length; i++)
215: {
216: cs = providers[i].charsetForName(charsetName);
217: if (cs != null)
218: break;
219: }
220: }
221: return cs;
222: }
223:
224: public static SortedMap availableCharsets()
225: {
226: TreeMap charsets = new TreeMap(String.CASE_INSENSITIVE_ORDER);
227: for (Iterator i = provider().charsets(); i.hasNext(); )
228: {
229: Charset cs = (Charset) i.next();
230: charsets.put(cs.name(), cs);
231: }
232:
233: CharsetProvider[] providers = providers2();
234: for (int j = 0; j < providers.length; j++)
235: {
236: for (Iterator i = providers[j].charsets(); i.hasNext(); )
237: {
238: Charset cs = (Charset) i.next();
239: charsets.put(cs.name(), cs);
240: }
241: }
242:
243: return Collections.unmodifiableSortedMap(charsets);
244: }
245:
246: private static CharsetProvider provider()
247: {
248: try
249: {
250: String s = System.getProperty("charset.provider");
251: if (s != null)
252: {
253: CharsetProvider p =
254: (CharsetProvider) ((Class.forName(s)).newInstance());
255: return p;
256: }
257: }
258: catch (Exception e)
259: {
260:
261: }
262:
263: return Provider.provider();
264: }
265:
266:
271: private static CharsetProvider[] providers2()
272: {
273: if (providers == null)
274: {
275: try
276: {
277: Iterator i = ServiceFactory.lookupProviders(CharsetProvider.class);
278: LinkedHashSet set = new LinkedHashSet();
279: while (i.hasNext())
280: set.add(i.next());
281:
282: providers = new CharsetProvider[set.size()];
283: set.toArray(providers);
284: }
285: catch (Exception e)
286: {
287: throw new RuntimeException(e);
288: }
289: }
290: return providers;
291: }
292:
293: public final String name ()
294: {
295: return canonicalName;
296: }
297:
298: public final Set aliases ()
299: {
300: if (aliases == null)
301: return Collections.EMPTY_SET;
302:
303:
304: int n = aliases.length;
305: HashSet aliasSet = new HashSet (n);
306: for (int i = 0; i < n; ++i)
307: aliasSet.add (aliases[i]);
308: return Collections.unmodifiableSet (aliasSet);
309: }
310:
311: public String displayName ()
312: {
313: return canonicalName;
314: }
315:
316: public String displayName (Locale locale)
317: {
318: return canonicalName;
319: }
320:
321: public final boolean isRegistered ()
322: {
323: return (!canonicalName.startsWith ("x-")
324: && !canonicalName.startsWith ("X-"));
325: }
326:
327: public abstract boolean contains (Charset cs);
328:
329: public abstract CharsetDecoder newDecoder ();
330:
331: public abstract CharsetEncoder newEncoder ();
332:
333: public boolean canEncode ()
334: {
335: return true;
336: }
337:
338:
339:
340:
341:
342: public final synchronized ByteBuffer encode (CharBuffer cb)
343: {
344: try
345: {
346: if (cachedEncoder == null)
347: {
348: cachedEncoder = newEncoder ()
349: .onMalformedInput (CodingErrorAction.REPLACE)
350: .onUnmappableCharacter (CodingErrorAction.REPLACE);
351: } else
352: cachedEncoder.reset();
353: return cachedEncoder.encode (cb);
354: }
355: catch (CharacterCodingException e)
356: {
357: throw new AssertionError (e);
358: }
359: }
360:
361: public final ByteBuffer encode (String str)
362: {
363: return encode (CharBuffer.wrap (str));
364: }
365:
366:
367:
368:
369:
370: public final synchronized CharBuffer decode (ByteBuffer bb)
371: {
372: try
373: {
374: if (cachedDecoder == null)
375: {
376: cachedDecoder = newDecoder ()
377: .onMalformedInput (CodingErrorAction.REPLACE)
378: .onUnmappableCharacter (CodingErrorAction.REPLACE);
379: } else
380: cachedDecoder.reset();
381:
382: return cachedDecoder.decode (bb);
383: }
384: catch (CharacterCodingException e)
385: {
386: throw new AssertionError (e);
387: }
388: }
389:
390: public final int compareTo (Object ob)
391: {
392: return canonicalName.compareToIgnoreCase (((Charset) ob).canonicalName);
393: }
394:
395: public final int hashCode ()
396: {
397: return canonicalName.hashCode ();
398: }
399:
400: public final boolean equals (Object ob)
401: {
402: if (ob instanceof Charset)
403: return canonicalName.equalsIgnoreCase (((Charset) ob).canonicalName);
404: else
405: return false;
406: }
407:
408: public final String toString ()
409: {
410: return canonicalName;
411: }
412: }