2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package java
.nio
.charset
;
41 import gnu
.java
.nio
.charset
.Provider
;
43 import java
.io
.BufferedReader
;
44 import java
.io
.InputStreamReader
;
46 import java
.nio
.ByteBuffer
;
47 import java
.nio
.CharBuffer
;
48 import java
.nio
.charset
.spi
.CharsetProvider
;
49 import java
.util
.Collections
;
50 import java
.util
.Enumeration
;
51 import java
.util
.HashSet
;
52 import java
.util
.Iterator
;
53 import java
.util
.LinkedHashSet
;
54 import java
.util
.Locale
;
56 import java
.util
.SortedMap
;
57 import java
.util
.TreeMap
;
60 * @author Jesse Rosenstock
63 public abstract class Charset
implements Comparable
65 private CharsetEncoder cachedEncoder
;
66 private CharsetDecoder cachedDecoder
;
71 private static CharsetProvider
[] providers
;
73 private final String canonicalName
;
74 private final String
[] aliases
;
76 protected Charset (String canonicalName
, String
[] aliases
)
78 checkName (canonicalName
);
81 int n
= aliases
.length
;
82 for (int i
= 0; i
< n
; ++i
)
83 checkName (aliases
[i
]);
88 this.canonicalName
= canonicalName
;
89 this.aliases
= aliases
;
93 * @throws IllegalCharsetNameException if the name is illegal
95 private static void checkName (String name
)
97 int n
= name
.length ();
100 throw new IllegalCharsetNameException (name
);
102 char ch
= name
.charAt (0);
103 if (!(('A' <= ch
&& ch
<= 'Z')
104 || ('a' <= ch
&& ch
<= 'z')
105 || ('0' <= ch
&& ch
<= '9')))
106 throw new IllegalCharsetNameException (name
);
108 for (int i
= 1; i
< n
; ++i
)
110 ch
= name
.charAt (i
);
111 if (!(('A' <= ch
&& ch
<= 'Z')
112 || ('a' <= ch
&& ch
<= 'z')
113 || ('0' <= ch
&& ch
<= '9')
114 || ch
== '-' || ch
== '.' || ch
== ':' || ch
== '_'))
115 throw new IllegalCharsetNameException (name
);
119 public static boolean isSupported (String charsetName
)
121 return charsetForName (charsetName
) != null;
125 * Returns the Charset instance for the charset of the given name.
129 * @throws UnsupportedCharsetException if this VM does not support
130 * the charset of the given name.
131 * @throws IllegalCharsetNameException if the given charset name is
133 * @throws IllegalArgumentException if <code>charsetName</code> is null.
135 public static Charset
forName (String charsetName
)
137 // Throws IllegalArgumentException as the JDK does.
138 if(charsetName
== null)
139 throw new IllegalArgumentException("Charset name must not be null.");
141 Charset cs
= charsetForName (charsetName
);
143 throw new UnsupportedCharsetException (charsetName
);
148 * Retrieves a charset for the given charset name.
150 * @return A charset object for the charset with the specified name, or
151 * <code>null</code> if no such charset exists.
153 * @throws IllegalCharsetNameException if the name is illegal
155 private static Charset
charsetForName(String charsetName
)
157 checkName (charsetName
);
159 CharsetProvider
[] providers
= providers2();
160 for (int i
= 0; i
< providers
.length
; i
++)
162 cs
= providers
[i
].charsetForName(charsetName
);
169 public static SortedMap
availableCharsets()
171 TreeMap charsets
= new TreeMap(String
.CASE_INSENSITIVE_ORDER
);
173 CharsetProvider
[] providers
= providers2();
174 for (int j
= 0; j
< providers
.length
; j
++)
176 for (Iterator i
= providers
[j
].charsets(); i
.hasNext(); )
178 Charset cs
= (Charset
) i
.next();
179 charsets
.put(cs
.name(), cs
);
183 return Collections
.unmodifiableSortedMap(charsets
);
186 private static CharsetProvider
provider()
190 String s
= System
.getProperty("charset.provider");
194 (CharsetProvider
) ((Class
.forName(s
)).newInstance());
203 return Provider
.provider();
207 * We need to support multiple providers, reading them from
208 * java.nio.charset.spi.CharsetProvider in the resource directory
211 private static CharsetProvider
[] providers2()
213 if (providers
== null)
217 Enumeration en
= ClassLoader
.getSystemResources
218 ("META-INF/services/java.nio.charset.spi.CharsetProvider");
219 LinkedHashSet set
= new LinkedHashSet();
221 while (en
.hasMoreElements())
223 BufferedReader rdr
= new BufferedReader(new InputStreamReader
224 (((URL
) (en
.nextElement())).openStream()));
227 String s
= rdr
.readLine();
231 (CharsetProvider
) ((Class
.forName(s
)).newInstance());
236 providers
= new CharsetProvider
[set
.size()];
237 set
.toArray(providers
);
241 throw new RuntimeException(e
);
247 public final String
name ()
249 return canonicalName
;
252 public final Set
aliases ()
255 return Collections
.EMPTY_SET
;
257 // should we cache the aliasSet instead?
258 int n
= aliases
.length
;
259 HashSet aliasSet
= new HashSet (n
);
260 for (int i
= 0; i
< n
; ++i
)
261 aliasSet
.add (aliases
[i
]);
262 return Collections
.unmodifiableSet (aliasSet
);
265 public String
displayName ()
267 return canonicalName
;
270 public String
displayName (Locale locale
)
272 return canonicalName
;
275 public final boolean isRegistered ()
277 return (!canonicalName
.startsWith ("x-")
278 && !canonicalName
.startsWith ("X-"));
281 public abstract boolean contains (Charset cs
);
283 public abstract CharsetDecoder
newDecoder ();
285 public abstract CharsetEncoder
newEncoder ();
287 public boolean canEncode ()
292 // NB: This implementation serializes different threads calling
293 // Charset.encode(), a potential performance problem. It might
294 // be better to remove the cache, or use ThreadLocal to cache on
295 // a per-thread basis.
296 public final synchronized ByteBuffer
encode (CharBuffer cb
)
300 if (cachedEncoder
== null)
302 cachedEncoder
= newEncoder ()
303 .onMalformedInput (CodingErrorAction
.REPLACE
)
304 .onUnmappableCharacter (CodingErrorAction
.REPLACE
);
306 cachedEncoder
.reset();
307 return cachedEncoder
.encode (cb
);
309 catch (CharacterCodingException e
)
311 throw new AssertionError (e
);
315 public final ByteBuffer
encode (String str
)
317 return encode (CharBuffer
.wrap (str
));
320 // NB: This implementation serializes different threads calling
321 // Charset.decode(), a potential performance problem. It might
322 // be better to remove the cache, or use ThreadLocal to cache on
323 // a per-thread basis.
324 public final synchronized CharBuffer
decode (ByteBuffer bb
)
328 if (cachedDecoder
== null)
330 cachedDecoder
= newDecoder ()
331 .onMalformedInput (CodingErrorAction
.REPLACE
)
332 .onUnmappableCharacter (CodingErrorAction
.REPLACE
);
334 cachedDecoder
.reset();
336 return cachedDecoder
.decode (bb
);
338 catch (CharacterCodingException e
)
340 throw new AssertionError (e
);
344 public final int compareTo (Object ob
)
346 return canonicalName
.compareToIgnoreCase (((Charset
) ob
).canonicalName
);
349 public final int hashCode ()
351 return canonicalName
.hashCode ();
354 public final boolean equals (Object ob
)
356 if (ob
instanceof Charset
)
357 return canonicalName
.equalsIgnoreCase (((Charset
) ob
).canonicalName
);
362 public final String
toString ()
364 return canonicalName
;