Charset.java revision c89c180eb85cc0392c3a6c2eb4803594478e665c
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.nio.charset;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughesimport com.ibm.icu4jni.charset.NativeConverter;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.BufferedReader;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStreamReader;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.URL;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.ByteBuffer;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.CharBuffer;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.spi.CharsetProvider;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessController;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PrivilegedAction;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collections;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Comparator;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Enumeration;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashSet;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Iterator;
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Locale;
38bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughesimport java.util.Map;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Set;
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.SortedMap;
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.TreeMap;
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
44c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * A charset is a named mapping between Unicode characters and byte sequences. Every
45c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * {@code Charset} can <i>decode</i>, converting a byte sequence into a sequence of characters,
46c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * and some can also <i>encode</i>, converting a sequence of characters into a byte sequence.
47c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * Use the method {@link #canEncode} to find out whether a charset supports both.
48c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes *
49c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <h4>Characters</h4>
50c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>In the context of this class, <i>character</i> always refers to a Java character: a Unicode
51c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * code point in the range U+0000 to U+FFFF. (Java represents supplementary characters using surrogates.)
52c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * Not all byte sequences will represent a character, and not
53c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * all characters can necessarily be represented by a given charset. The method {@link #contains}
54c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * can be used to determine whether every character representable by one charset can also be
55c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * represented by another (meaning that a lossless transformation is possible from the contained
56c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * to the container).
57c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes *
58c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <h4>Encodings</h4>
59c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>There are many possible ways to represent Unicode characters as byte sequences.
60c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * See <a href="http://www.unicode.org/reports/tr17/">UTR#17: Unicode Character Encoding Model</a>
61c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * for detailed discussion.
62c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
63c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>The most important mappings capable of representing every character are the Unicode
64c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * Transformation Format (UTF) charsets. Of those, UTF-8 and the UTF-16 family are the most
65c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * common. UTF-8 (described in <a href="http://www.ietf.org/rfc/rfc3629.txt">RFC 3629</a>)
66c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * encodes a character using 1 to 4 bytes. UTF-16 uses exactly 2 bytes per character (potentially
67c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * wasting space, but allowing efficient random access into BMP text), and UTF-32 uses
68c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * exactly 4 bytes per character (trading off even more space for efficient random access into text
69c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * that includes supplementary characters).
70c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
71c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>UTF-16 and UTF-32 encode characters directly, using their code point as a two- or four-byte
72c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * integer. This means that any given UTF-16 or UTF-32 byte sequence is either big- or
73c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * little-endian. To assist decoders, Unicode includes a special <i>byte order mark</i> (BOM)
74c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * character U+FEFF used to determine the endianness of a sequence. The corresponding byte-swapped
75c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * code point U+FFFE is guaranteed never to be assigned. If a UTF-16 decoder sees
76c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * {@code 0xfe, 0xff}, for example, it knows it's reading a big-endian byte sequence, while
77c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * {@code 0xff, 0xfe}, would indicate a little-endian byte sequence.
78c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
79c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>UTF-8 can contain a BOM, but since the UTF-8 encoding of a character always uses the same
80c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * byte sequence, there is no information about endianness to convey. Seeing the bytes
81c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * corresponding to the UTF-8 encoding of U+FEFF ({@code 0xef, 0xbb, 0xbf}) would only serve to
82c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * suggest that you're reading UTF-8. Note that BOMs are decoded as the U+FEFF character, and
83c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * will appear in the output character sequence. This means that a disadvantage to including a BOM
84c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * in UTF-8 is that most applications that use UTF-8 do not expect to see a BOM. (This is also a
85c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * reason to prefer UTF-8: it's one less complication to worry about.)
86c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
87c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>Because a BOM indicates how the data that follows should be interpreted, a BOM should occur
88c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * as the first character in a character sequence.
89c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
90c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>See the <a href="http://unicode.org/faq/utf_bom.html#BOM">Byte Order Mark (BOM) FAQ</a> for
91c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * more about dealing with BOMs.
92c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
93c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <h4>Endianness and BOM behavior</h4>
94c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
95c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>The following tables show the endianness and BOM behavior of the UTF-16 variants.
96c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
97c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>This table shows what the encoder writes. "BE" means that the byte sequence is big-endian,
98c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * "LE" means little-endian. "BE BOM" means a big-endian BOM (that is, {@code 0xfe, 0xff}).
99c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p><table width="100%">
100c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <tr> <th>Charset</th>  <th>Encoder writes</th>  </tr>
101c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <tr> <td>UTF-16BE</td> <td>BE, no BOM</td>      </tr>
102c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <tr> <td>UTF-16LE</td> <td>LE, no BOM</td>      </tr>
103c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <tr> <td>UTF-16</td>   <td>BE, with BE BOM</td> </tr>
104c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * </table>
105c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
106c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>The next table shows how each variant's decoder behaves when reading a byte sequence.
107c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * The exact meaning of "failure" in the table is dependent on the
108c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * {@link CodingErrorAction} supplied to {@link CharsetDecoder#malformedInputAction}, so
109c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * "BE, failure" means "the byte sequence is treated as big-endian, and a little-endian BOM
110c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * triggers the malformedInputAction".
111c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
112c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>The phrase "includes BOM" means that the output includes the U+FEFF byte order mark character.
113c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
114c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p><table width="100%">
115c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <tr> <th>Charset</th>  <th>BE BOM</th>           <th>LE BOM</th>           <th>No BOM</th> </tr>
116c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <tr> <td>UTF-16BE</td> <td>BE, includes BOM</td> <td>BE, failure</td>      <td>BE</td>     </tr>
117c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <tr> <td>UTF-16LE</td> <td>LE, failure</td>      <td>LE, includes BOM</td> <td>LE</td>     </tr>
118c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <tr> <td>UTF-16</td>   <td>BE, includes BOM</td> <td>LE, includes BOM</td> <td>BE</td>     </tr>
119c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * </table>
120c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
121c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <h4>Charset names</h4>
122c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>A charset has a canonical name, returned by {@link #name}. Most charsets will
123c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * also have one or more aliases, returned by {@link #aliases}. A charset can be looked up
124c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * by canonical name or any of its aliases using {@link #forName}.
125c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
126c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <h4>Guaranteed-available charsets</h4>
127c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>The following charsets are available on every Java implementation:
128c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes * <ul>
129c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes * <li>ISO-8859-1
130c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes * <li>US-ASCII
131c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes * <li>UTF-16
132c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes * <li>UTF-16BE
133c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes * <li>UTF-16LE
134c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes * <li>UTF-8
135c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes * </ul>
136c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>All of these charsets support both decoding and encoding. The charsets whose names begin
137c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * "UTF" can represent all characters, as mentioned above. The "ISO-8859-1" and "US-ASCII" charsets
138c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * can only represent small subsets of these characters. Except when required to do otherwise for
139c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * compatibility, new code should use one of the UTF charsets listed above. The platform's default
140c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * charset is UTF-8. (This is in contrast to some older implementations, where the default charset
141c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * depended on the user's locale.)
142c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes *
143c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>Most implementations will support hundreds of charsets. Use {@link #availableCharsets} or
144c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * {@link #isSupported} to see what's available. If you intend to use the charset if it's
145c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * available, just call {@link #forName} and catch the exceptions it throws if the charset isn't
146c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * available.
147c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes *
148c60bc1815dca549f3fb4e572f6aac749d7fa9fc6Elliott Hughes * <p>Additional charsets can be made available by configuring one or more charset
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * providers through provider configuration files. Such files are always named
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * as "java.nio.charset.spi.CharsetProvider" and located in the
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * "META-INF/services" sub folder of one or more classpaths. The files should be
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * encoded in "UTF-8". Each line of their content specifies the class name of a
153c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * charset provider which extends {@link java.nio.charset.spi.CharsetProvider}.
154c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * A line should end with '\r', '\n' or '\r\n'. Leading and trailing whitespaces
155c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * are trimmed. Blank lines, and lines (after trimming) starting with "#" which are
156c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * regarded as comments, are both ignored. Duplicates of names already found are also
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * ignored. Both the configuration files and the provider classes will be loaded
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * using the thread context class loader.
159eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson *
160c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * <p>Although class is thread-safe, the {@link CharsetDecoder} and {@link CharsetEncoder} instances
161c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes * it returns are inherently stateful.
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class Charset implements Comparable<Charset> {
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
165eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * The name of configuration files where charset provider class names can be
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specified.
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
168f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    private static final String PROVIDER_CONFIGURATION_FILE_NAME = "META-INF/services/java.nio.charset.spi.CharsetProvider";
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
171eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * The encoding of configuration files
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
173f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    private static final String PROVIDER_CONFIGURATION_FILE_ENCODING = "UTF-8";
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
176eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * The comment string used in configuration files
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
178f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    private static final String PROVIDER_CONFIGURATION_FILE_COMMENT = "#";
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static ClassLoader systemClassLoader;
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
182ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes    private static SortedMap<String, Charset> cachedBuiltInCharsets;
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final String canonicalName;
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // the aliases set
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final HashSet<String> aliasesSet;
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // cached Charset table
190eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private final static HashMap<String, Charset> cachedCharsetTable = new HashMap<String, Charset>();
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
192eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private static boolean inForNameInternal = false;
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a <code>Charset</code> object. Duplicated aliases are
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * ignored.
197f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param canonicalName
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the canonical name of the charset.
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param aliases
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            an array containing all aliases of the charset. May be null.
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalCharsetNameException
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             on an illegal value being supplied for either
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             <code>canonicalName</code> or for any element of
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             <code>aliases</code>.
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
207eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    protected Charset(String canonicalName, String[] aliases) {
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (null == canonicalName) {
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check whether the given canonical name is legal
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkCharsetName(canonicalName);
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.canonicalName = canonicalName;
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check each alias and put into a set
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.aliasesSet = new HashSet<String>();
216bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (aliases != null) {
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 0; i < aliases.length; i++) {
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                checkCharsetName(aliases[i]);
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                this.aliasesSet.add(aliases[i]);
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks whether a character is a special character that can be used in
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * charset names, other than letters and digits.
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static boolean isSpecial(char c) {
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return ('-' == c || '.' == c || ':' == c || '_' == c);
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks whether a character is a letter (ascii) which are defined in the
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * spec.
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static boolean isLetter(char c) {
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks whether a character is a digit (ascii) which are defined in the
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * spec.
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static boolean isDigit(char c) {
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return ('0' <= c && c <= '9');
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks whether a given string is a legal charset name. The argument name
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * should not be null.
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static void checkCharsetName(String name) {
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // An empty string is illegal charset name
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (name.length() == 0) {
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalCharsetNameException(name);
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // The first character must be a letter or a digit
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // This is related to HARMONY-68 (won't fix)
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // char first = name.charAt(0);
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // if (!isLetter(first) && !isDigit(first)) {
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // throw new IllegalCharsetNameException(name);
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // }
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Check the remaining characters
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length = name.length();
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = 0; i < length; i++) {
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            char c = name.charAt(i);
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!isLetter(c) && !isDigit(c) && !isSpecial(c)) {
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalCharsetNameException(name);
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Use privileged code to get the context class loader.
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static ClassLoader getContextClassLoader() {
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        final Thread t = Thread.currentThread();
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return AccessController
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .doPrivileged(new PrivilegedAction<ClassLoader>() {
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    public ClassLoader run() {
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        return t.getContextClassLoader();
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                });
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Use privileged code to get the system class loader.
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static void getSystemClassLoader() {
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (null == systemClassLoader) {
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            systemClassLoader = AccessController
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .doPrivileged(new PrivilegedAction<ClassLoader>() {
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        public ClassLoader run() {
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            return ClassLoader.getSystemClassLoader();
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    });
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Add the charsets supported by the given provider to the map.
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
303bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    private static void addCharsets(CharsetProvider cp, Map<String, Charset> charsets) {
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Iterator<Charset> it = cp.charsets();
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (it.hasNext()) {
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Charset cs = it.next();
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Only new charsets will be added
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!charsets.containsKey(cs.name())) {
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                charsets.put(cs.name(), cs);
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Trim comment string, and then trim white spaces.
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static String trimClassName(String name) {
318c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes        String trimmedName = name;
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int index = name.indexOf(PROVIDER_CONFIGURATION_FILE_COMMENT);
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Trim comments
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (index != -1) {
322c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes            trimmedName = name.substring(0, index);
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
324c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes        return trimmedName.trim();
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Read a configuration file and add the charsets supported by the providers
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specified by this configuration file to the map.
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static void loadConfiguredCharsets(URL configFile,
332bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            ClassLoader contextClassLoader, Map<String, Charset> charsets) {
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        BufferedReader reader = null;
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            InputStream is = configFile.openStream();
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Read each line for charset provider class names
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            reader = new BufferedReader(new InputStreamReader(is,
338b748a9b827665a8b19d60af4b419503b45e74329Elliott Hughes                    PROVIDER_CONFIGURATION_FILE_ENCODING));
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String providerClassName = reader.readLine();
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (null != providerClassName) {
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                providerClassName = trimClassName(providerClassName);
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Skip comments and blank lines
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (providerClassName.length() > 0) { // Non empty string
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Load the charset provider
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Object cp = null;
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        Class<?> c = Class.forName(providerClassName, true,
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                contextClassLoader);
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        cp = c.newInstance();
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } catch (Exception ex) {
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // try to use system classloader when context
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // classloader failed to load config file.
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        try {
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            getSystemClassLoader();
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            Class<?> c = Class.forName(providerClassName, true,
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    systemClassLoader);
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            cp = c.newInstance();
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        } catch (Exception e) {
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            throw new Error(e.getMessage(), e);
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Put the charsets supported by this provider into the map
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    addCharsets((CharsetProvider) cp, charsets);
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Read the next line of the config file
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                providerClassName = reader.readLine();
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException ex) {
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Can't read this configuration file, ignore
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (null != reader) {
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    reader.close();
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (IOException ex) {
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Ignore closing exception
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
381ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes    private static synchronized SortedMap<String, Charset> getCachedBuiltInCharsets() {
382ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes        if (cachedBuiltInCharsets == null) {
383ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes            cachedBuiltInCharsets = new TreeMap<String, Charset>(String.CASE_INSENSITIVE_ORDER);
384ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes            for (String charsetName : NativeConverter.getAvailableCharsetNames()) {
385ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes                Charset charset = NativeConverter.charsetForName(charsetName);
386ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes                cachedBuiltInCharsets.put(charset.name(), charset);
387ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes            }
388ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes        }
389ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes        return cachedBuiltInCharsets;
390ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes    }
391ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
393ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes     * Returns an immutable case-insensitive map from canonical names to {@code Charset} instances.
394ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes     * If multiple charsets have the same canonical name, it is unspecified which is returned in
395ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes     * the map. This method may be slow. If you know which charset you're looking for, use
396ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes     * {@link #forName}.
397ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes     * @return an immutable case-insensitive map from canonical names to {@code Charset} instances
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @SuppressWarnings("unchecked")
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static SortedMap<String, Charset> availableCharsets() {
401ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes        // Start with a copy of the built-in charsets...
402ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes        TreeMap<String, Charset> charsets = new TreeMap<String, Charset>(String.CASE_INSENSITIVE_ORDER);
403ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes        charsets.putAll(getCachedBuiltInCharsets());
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
405bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        // Add all charsets provided by charset providers...
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ClassLoader contextClassLoader = getContextClassLoader();
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Enumeration<URL> e = null;
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
409bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            if (contextClassLoader != null) {
410bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                e = contextClassLoader.getResources(PROVIDER_CONFIGURATION_FILE_NAME);
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                getSystemClassLoader();
413bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                e = systemClassLoader.getResources(PROVIDER_CONFIGURATION_FILE_NAME);
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Examine each configuration file
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (e.hasMoreElements()) {
417bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                loadConfiguredCharsets(e.nextElement(), contextClassLoader, charsets);
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException ex) {
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Unexpected ClassLoader exception, ignore
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return Collections.unmodifiableSortedMap(charsets);
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Read a configuration file and try to find the desired charset among those
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * which are supported by the providers specified in this configuration
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * file.
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static Charset searchConfiguredCharsets(String charsetName,
431adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ClassLoader contextClassLoader, URL configFile) {
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        BufferedReader reader = null;
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            InputStream is = configFile.openStream();
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Read each line for charset provider class names
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            reader = new BufferedReader(new InputStreamReader(is,
437b748a9b827665a8b19d60af4b419503b45e74329Elliott Hughes                    PROVIDER_CONFIGURATION_FILE_ENCODING));
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String providerClassName = reader.readLine();
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (null != providerClassName) {
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                providerClassName = trimClassName(providerClassName);
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (providerClassName.length() > 0) { // Non empty string
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Load the charset provider
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Object cp = null;
444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        Class<?> c = Class.forName(providerClassName, true,
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                contextClassLoader);
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        cp = c.newInstance();
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } catch (Exception ex) {
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // try to use system classloader when context
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // classloader failed to load config file.
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        try {
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            getSystemClassLoader();
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            Class<?> c = Class.forName(providerClassName, true,
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    systemClassLoader);
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            cp = c.newInstance();
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        } catch (SecurityException e) {
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            // BEGIN android-changed
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            // ignore
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            // END android-changed
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        } catch (Exception e) {
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            throw new Error(e.getMessage(), e);
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // BEGIN android-changed
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (cp != null) {
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // Try to get the desired charset from this provider
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        Charset cs = ((CharsetProvider) cp)
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                .charsetForName(charsetName);
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (null != cs) {
470adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            return cs;
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // END android-changed
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Read the next line of the config file
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                providerClassName = reader.readLine();
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException ex) {
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Can't read this configuration file
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (null != reader) {
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    reader.close();
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (IOException ex) {
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Ignore closing exception
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
494eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * Gets a <code>Charset</code> instance for the specified charset name. If
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the charset is not supported, returns null instead of throwing an
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * exception.
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
498eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private synchronized static Charset forNameInternal(String charsetName)
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IllegalCharsetNameException {
500eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
501bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        Charset cs = lookupCachedOrBuiltInCharset(charsetName);
502bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (cs != null || inForNameInternal) {
503eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            return cs;
504eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        }
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
506eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        // collect all charsets provided by charset providers
507eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        try {
508bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            Enumeration<URL> e = null;
509bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            ClassLoader contextClassLoader = getContextClassLoader();
510bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            if (contextClassLoader != null) {
511bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                e = contextClassLoader.getResources(PROVIDER_CONFIGURATION_FILE_NAME);
512eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            } else {
513eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                getSystemClassLoader();
514eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                if (systemClassLoader == null) {
515eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    // Non available during class library start-up phase
516bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                    return null;
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
518bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                    e = systemClassLoader.getResources(PROVIDER_CONFIGURATION_FILE_NAME);
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
520eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            }
521eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
522eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            // examine each configuration file
523eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            while (e.hasMoreElements()) {
524bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                inForNameInternal = true;
525bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                cs = searchConfiguredCharsets(charsetName, contextClassLoader, e.nextElement());
526bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                inForNameInternal = false;
527bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                if (cs != null) {
528eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    cacheCharset(cs);
529eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    return cs;
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
532eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        } catch (IOException ex) {
533eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            // Unexpected ClassLoader exception, ignore
534eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        } finally {
535bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            inForNameInternal = false;
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
540bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    private synchronized static Charset lookupCachedOrBuiltInCharset(String charsetName) {
541bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        Charset cs = cachedCharsetTable.get(charsetName);
542bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (cs != null) {
543bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            return cs;
544bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        }
545bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (charsetName == null) {
546bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            throw new IllegalArgumentException();
547bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        }
548bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        checkCharsetName(charsetName);
549ccb8b92211a3e87acaf6486c8d4423c2053b8b5eElliott Hughes        cs = NativeConverter.charsetForName(charsetName);
550bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (cs != null) {
551bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            cacheCharset(cs);
552bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        }
553bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        return cs;
554bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    }
555bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * save charset into cachedCharsetTable
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
559bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    private synchronized static void cacheCharset(Charset cs) {
560bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        // Cache the Charset by its canonical name...
561bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        String canonicalName = cs.name();
562bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (!cachedCharsetTable.containsKey(canonicalName)) {
563bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            cachedCharsetTable.put(canonicalName, cs);
564eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        }
565bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        // And all its aliases...
566bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        for (String alias : cs.aliasesSet) {
567bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            if (!cachedCharsetTable.containsKey(alias)) {
568bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                cachedCharsetTable.put(alias, cs);
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
572adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
573adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a <code>Charset</code> instance for the specified charset name.
575f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param charsetName
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the canonical name of the charset or an alias.
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a <code>Charset</code> instance for the specified charset name.
579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalCharsetNameException
580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified charset name is illegal.
581adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws UnsupportedCharsetException
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the desired charset is not supported by this runtime.
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
584eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    public static Charset forName(String charsetName) {
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Charset c = forNameInternal(charsetName);
586bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (c == null) {
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnsupportedCharsetException(charsetName);
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return c;
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Determines whether the specified charset is supported by this runtime.
594f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param charsetName
596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the charset.
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if the specified charset is supported, otherwise false.
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalCharsetNameException
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified charset name is illegal.
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
601eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    public static synchronized boolean isSupported(String charsetName) {
602bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        return forNameInternal(charsetName) != null;
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
606c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * Determines whether this charset is a superset of the given charset. A charset C1 contains
607c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * charset C2 if every character representable by C2 is also representable by C1. This means
608c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * that lossless conversion is possible from C2 to C1 (but not necessarily the other way
609c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * round). It does <i>not</i> imply that the two charsets use the same byte sequences for the
610c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * characters they share.
611c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     *
612c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * <p>Note that this method is allowed to be conservative, and some implementations may return
613c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * false when this charset does contain the other charset. Android's implementation is precise,
614c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * and will always return true in such cases.
615f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param charset
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            a given charset.
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if this charset is a super set of the given charset,
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         false if it's unknown or this charset is not a superset of
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         the given charset.
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public abstract boolean contains(Charset charset);
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a new instance of an encoder for this charset.
626f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a new instance of an encoder for this charset.
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public abstract CharsetEncoder newEncoder();
630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a new instance of a decoder for this charset.
633f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a new instance of a decoder for this charset.
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public abstract CharsetDecoder newDecoder();
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the canonical name of this charset.
640f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this charset's name in canonical form.
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final String name() {
644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.canonicalName;
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the set of this charset's aliases.
649f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an unmodifiable set of this charset's aliases.
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Set<String> aliases() {
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return Collections.unmodifiableSet(this.aliasesSet);
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the name of this charset for the default locale.
658f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
659eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * <p>The default implementation returns the canonical name of this charset.
660eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * Subclasses may return a localized display name.
661eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the name of this charset for the default locale.
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String displayName() {
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.canonicalName;
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the name of this charset for the specified locale.
670eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
671eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * <p>The default implementation returns the canonical name of this charset.
672eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * Subclasses may return a localized display name.
673eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param l
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            a certain locale
676eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * @return the name of this charset for the specified locale
677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String displayName(Locale l) {
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.canonicalName;
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates whether this charset is known to be registered in the IANA
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Charset Registry.
685f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if the charset is known to be registered, otherwise returns
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         false.
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final boolean isRegistered() {
690f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        return !canonicalName.startsWith("x-")
691f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                && !canonicalName.startsWith("X-");
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns true if this charset supports encoding, false otherwise.
696f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if this charset supports encoding, false otherwise.
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canEncode() {
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return true;
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
704c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * Returns a new {@code ByteBuffer} containing the bytes encoding the characters from
705c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * {@code buffer}.
706c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * This method uses {@code CodingErrorAction.REPLACE}.
707c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     *
708c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * <p>Applications should generally create a {@link CharsetEncoder} using {@link #newEncoder}
709c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * for performance.
710eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param buffer
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the character buffer containing the content to be encoded.
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the result of the encoding.
714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
715eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    public final ByteBuffer encode(CharBuffer buffer) {
716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
717c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes            return newEncoder()
718eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    .onMalformedInput(CodingErrorAction.REPLACE)
719eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    .onUnmappableCharacter(CodingErrorAction.REPLACE).encode(
720eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                            buffer);
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (CharacterCodingException ex) {
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new Error(ex.getMessage(), ex);
723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
727c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * Returns a new {@code ByteBuffer} containing the bytes encoding the characters from {@code s}.
728c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * This method uses {@code CodingErrorAction.REPLACE}.
729eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
730c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * <p>Applications should generally create a {@link CharsetEncoder} using {@link #newEncoder}
731c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * for performance.
732c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     *
733c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * @param s the string to be encoded.
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the result of the encoding.
735adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final ByteBuffer encode(String s) {
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return encode(CharBuffer.wrap(s));
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
741c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * Returns a new {@code CharBuffer} containing the characters decoded from {@code buffer}.
742c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * This method uses {@code CodingErrorAction.REPLACE}.
743c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     *
744c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * <p>Applications should generally create a {@link CharsetDecoder} using {@link #newDecoder}
745c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * for performance.
746f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param buffer
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the byte buffer containing the content to be decoded.
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a character buffer containing the output of the decoding.
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharBuffer decode(ByteBuffer buffer) {
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
753c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes            return newDecoder()
754eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    .onMalformedInput(CodingErrorAction.REPLACE)
755c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes                    .onUnmappableCharacter(CodingErrorAction.REPLACE).decode(buffer);
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (CharacterCodingException ex) {
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new Error(ex.getMessage(), ex);
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -------------------------------------------------------------------
763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Methods implementing parent interface Comparable
764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -------------------------------------------------------------------
765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
766adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
768c89c180eb85cc0392c3a6c2eb4803594478e665cElliott Hughes     * Compares this charset with the given charset. This comparison is
769adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * based on the case insensitive canonical names of the charsets.
770f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param charset
772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given object to be compared with.
773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a negative integer if less than the given object, a positive
774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         integer if larger than it, or 0 if equal to it.
775adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int compareTo(Charset charset) {
777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.canonicalName.compareToIgnoreCase(charset.canonicalName);
778adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
781adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -------------------------------------------------------------------
782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Methods overriding parent class Object
783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -------------------------------------------------------------------
784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
785adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
786adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Determines whether this charset equals to the given object. They are
788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * considered to be equal if they have the same canonical name.
789f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param obj
791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given object to be compared with.
792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if they have the same canonical name, otherwise false.
793adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
794adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final boolean equals(Object obj) {
796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (obj instanceof Charset) {
797adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Charset that = (Charset) obj;
798adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return this.canonicalName.equals(that.canonicalName);
799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
800adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return false;
801adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
802adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
804adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the hash code of this charset.
805f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
806adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the hash code of this charset.
807adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
808adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
809adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int hashCode() {
810adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.canonicalName.hashCode();
811adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
812adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
813adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
814adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a string representation of this charset. Usually this contains the
815adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * canonical name of the charset.
816f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
817adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a string representation of this charset.
818adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
819adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
820adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final String toString() {
821f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        return "Charset[" + this.canonicalName + "]";
822adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
823adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
824adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
825adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the system default charset from the virtual machine.
826f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
827adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the default charset.
828adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
829adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static Charset defaultCharset() {
830adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Charset defaultCharset = null;
831adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String encoding = AccessController
832adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .doPrivileged(new PrivilegedAction<String>() {
833adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    public String run() {
834f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                        return System.getProperty("file.encoding");
835adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
836adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                });
837adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
838adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            defaultCharset = Charset.forName(encoding);
839adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (UnsupportedCharsetException e) {
840f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            defaultCharset = Charset.forName("UTF-8");
841adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
842adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return defaultCharset;
843adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
844adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
845