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.classpath.ServiceFactory;
42 import gnu.classpath.SystemProperties;
43 import gnu.java.nio.charset.Provider;
44 import gnu.java.nio.charset.iconv.IconvProvider;
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.HashSet;
51 import java.util.Iterator;
52 import java.util.LinkedHashSet;
53 import java.util.Locale;
55 import java.util.SortedMap;
56 import java.util.TreeMap;
59 * @author Jesse Rosenstock
61 * @status updated to 1.5
63 public abstract class Charset implements Comparable<Charset>
65 private CharsetEncoder cachedEncoder;
66 private CharsetDecoder cachedDecoder;
69 * Extra Charset providers.
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);
120 * Returns the system default charset.
122 * This may be set by the user or VM with the file.encoding
127 public static Charset defaultCharset()
133 encoding = SystemProperties.getProperty("file.encoding");
135 catch(SecurityException e)
138 encoding = "ISO-8859-1";
140 catch(IllegalArgumentException e)
143 encoding = "ISO-8859-1";
148 return forName(encoding);
150 catch(UnsupportedCharsetException e)
154 catch(IllegalCharsetNameException e)
158 catch(IllegalArgumentException e)
163 throw new IllegalStateException("Can't get default charset!");
166 public static boolean isSupported (String charsetName)
168 return charsetForName (charsetName) != null;
172 * Returns the Charset instance for the charset of the given name.
175 * @return the Charset instance for the indicated charset
176 * @throws UnsupportedCharsetException if this VM does not support
177 * the charset of the given name.
178 * @throws IllegalCharsetNameException if the given charset name is
180 * @throws IllegalArgumentException if <code>charsetName</code> is null.
182 public static Charset forName (String charsetName)
184 // Throws IllegalArgumentException as the JDK does.
185 if(charsetName == null)
186 throw new IllegalArgumentException("Charset name must not be null.");
188 Charset cs = charsetForName (charsetName);
190 throw new UnsupportedCharsetException (charsetName);
195 * Retrieves a charset for the given charset name.
197 * @return A charset object for the charset with the specified name, or
198 * <code>null</code> if no such charset exists.
200 * @throws IllegalCharsetNameException if the name is illegal
202 private static Charset charsetForName(String charsetName)
204 checkName (charsetName);
205 // Try the default provider first
206 // (so we don't need to load external providers unless really necessary)
207 // if it is an exotic charset try loading the external providers.
208 Charset cs = provider().charsetForName(charsetName);
211 CharsetProvider[] providers = providers2();
212 for (int i = 0; i < providers.length; i++)
214 cs = providers[i].charsetForName(charsetName);
222 public static SortedMap<String, Charset> availableCharsets()
224 TreeMap<String, Charset> charsets
225 = new TreeMap(String.CASE_INSENSITIVE_ORDER);
226 for (Iterator<Charset> i = provider().charsets(); i.hasNext(); )
228 Charset cs = i.next();
229 charsets.put(cs.name(), cs);
232 CharsetProvider[] providers = providers2();
233 for (int j = 0; j < providers.length; j++)
235 for (Iterator<Charset> i = providers[j].charsets(); i.hasNext(); )
237 Charset cs = (Charset) i.next();
238 charsets.put(cs.name(), cs);
242 return Collections.unmodifiableSortedMap(charsets);
245 private static CharsetProvider provider()
247 String useIconv = SystemProperties.getProperty
248 ("gnu.classpath.nio.charset.provider.iconv");
250 if (useIconv != null)
251 return IconvProvider.provider();
253 return Provider.provider();
257 * We need to support multiple providers, reading them from
258 * java.nio.charset.spi.CharsetProvider in the resource directory
259 * META-INF/services. This returns the "extra" charset providers.
261 private static CharsetProvider[] providers2()
263 if (providers == null)
267 Iterator i = ServiceFactory.lookupProviders(CharsetProvider.class);
268 LinkedHashSet set = new LinkedHashSet();
272 providers = new CharsetProvider[set.size()];
273 set.toArray(providers);
277 throw new RuntimeException(e);
283 public final String name ()
285 return canonicalName;
288 public final Set<String> aliases ()
291 return Collections.<String>emptySet();
293 // should we cache the aliasSet instead?
294 int n = aliases.length;
295 HashSet<String> aliasSet = new HashSet<String> (n);
296 for (int i = 0; i < n; ++i)
297 aliasSet.add (aliases[i]);
298 return Collections.unmodifiableSet (aliasSet);
301 public String displayName ()
303 return canonicalName;
306 public String displayName (Locale locale)
308 return canonicalName;
311 public final boolean isRegistered ()
313 return (!canonicalName.startsWith ("x-")
314 && !canonicalName.startsWith ("X-"));
317 public abstract boolean contains (Charset cs);
319 public abstract CharsetDecoder newDecoder ();
321 public abstract CharsetEncoder newEncoder ();
323 public boolean canEncode ()
328 // NB: This implementation serializes different threads calling
329 // Charset.encode(), a potential performance problem. It might
330 // be better to remove the cache, or use ThreadLocal to cache on
331 // a per-thread basis.
332 public final synchronized ByteBuffer encode (CharBuffer cb)
336 if (cachedEncoder == null)
338 cachedEncoder = newEncoder ()
339 .onMalformedInput (CodingErrorAction.REPLACE)
340 .onUnmappableCharacter (CodingErrorAction.REPLACE);
342 cachedEncoder.reset();
343 return cachedEncoder.encode (cb);
345 catch (CharacterCodingException e)
347 throw new AssertionError (e);
351 public final ByteBuffer encode (String str)
353 return encode (CharBuffer.wrap (str));
356 // NB: This implementation serializes different threads calling
357 // Charset.decode(), a potential performance problem. It might
358 // be better to remove the cache, or use ThreadLocal to cache on
359 // a per-thread basis.
360 public final synchronized CharBuffer decode (ByteBuffer bb)
364 if (cachedDecoder == null)
366 cachedDecoder = newDecoder ()
367 .onMalformedInput (CodingErrorAction.REPLACE)
368 .onUnmappableCharacter (CodingErrorAction.REPLACE);
370 cachedDecoder.reset();
372 return cachedDecoder.decode (bb);
374 catch (CharacterCodingException e)
376 throw new AssertionError (e);
380 public final int compareTo (Charset other)
382 return canonicalName.compareToIgnoreCase (other.canonicalName);
385 public final int hashCode ()
387 return canonicalName.hashCode ();
390 public final boolean equals (Object ob)
392 if (ob instanceof Charset)
393 return canonicalName.equalsIgnoreCase (((Charset) ob).canonicalName);
398 public final String toString ()
400 return canonicalName;