Charset.java revision bcf7c66e617ad0c33bb320184bb2401def517342
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
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.BufferedReader;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStreamReader;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.URL;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.ByteBuffer;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.CharBuffer;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.charset.spi.CharsetProvider;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessController;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PrivilegedAction;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collections;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Comparator;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Enumeration;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashSet;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Iterator;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Locale;
37bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughesimport java.util.Map;
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Set;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.SortedMap;
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.TreeMap;
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
42eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson// BEGIN android-changed
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport com.ibm.icu4jni.charset.CharsetProviderICU;
44eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson// END android-changed
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * A charset defines a mapping between a Unicode character sequence and a byte
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * sequence. It facilitates the encoding from a Unicode character sequence into
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * a byte sequence, and the decoding from a byte sequence into a Unicode
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * character sequence.
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * A charset has a canonical name, which is usually in uppercase. Typically it
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * also has one or more aliases. The name string can only consist of the
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * following characters: '0' - '9', 'A' - 'Z', 'a' - 'z', '.', ':'. '-' and '_'.
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The first character of the name must be a digit or a letter.
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The following charsets should be supported by any java platform: US-ASCII,
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * ISO-8859-1, UTF-8, UTF-16BE, UTF-16LE, UTF-16.
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Additional charsets can be made available by configuring one or more charset
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * providers through provider configuration files. Such files are always named
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * as "java.nio.charset.spi.CharsetProvider" and located in the
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * "META-INF/services" sub folder of one or more classpaths. The files should be
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * encoded in "UTF-8". Each line of their content specifies the class name of a
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * charset provider which extends
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <code>java.nio.charset.spi.CharsetProvider</code>. A line should end with
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * '\r', '\n' or '\r\n'. Leading and trailing whitespaces are trimmed. Blank
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * lines, and lines (after trimming) starting with "#" which are regarded as
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * comments, are both ignored. Duplicates of names already found are also
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * ignored. Both the configuration files and the provider classes will be loaded
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * using the thread context class loader.
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This class is thread-safe.
74eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson *
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.nio.charset.spi.CharsetProvider
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class Charset implements Comparable<Charset> {
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
80eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * The name of configuration files where charset provider class names can be
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specified.
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final String PROVIDER_CONFIGURATION_FILE_NAME = "META-INF/services/java.nio.charset.spi.CharsetProvider"; //$NON-NLS-1$
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
86eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * The encoding of configuration files
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final String PROVIDER_CONFIGURATION_FILE_ENCODING = "UTF-8"; //$NON-NLS-1$
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
91eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * The comment string used in configuration files
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final String PROVIDER_CONFIGURATION_FILE_COMMENT = "#"; //$NON-NLS-1$
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static ClassLoader systemClassLoader;
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // built in provider instance, assuming thread-safe
98eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    // BEGIN android-changed
99bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    private static final CharsetProviderICU _builtInProvider = new CharsetProviderICU();
100eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    // END android-changed
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // cached built in charsets
103bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    private static SortedMap<String, Charset> _builtInCharsets = null;
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final String canonicalName;
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // the aliases set
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private final HashSet<String> aliasesSet;
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    // cached Charset table
111eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private final static HashMap<String, Charset> cachedCharsetTable = new HashMap<String, Charset>();
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
113eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private static boolean inForNameInternal = false;
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a <code>Charset</code> object. Duplicated aliases are
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * ignored.
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param canonicalName
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the canonical name of the charset.
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param aliases
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            an array containing all aliases of the charset. May be null.
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalCharsetNameException
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             on an illegal value being supplied for either
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             <code>canonicalName</code> or for any element of
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             <code>aliases</code>.
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
128eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    protected Charset(String canonicalName, String[] aliases) {
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (null == canonicalName) {
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new NullPointerException();
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check whether the given canonical name is legal
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkCharsetName(canonicalName);
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.canonicalName = canonicalName;
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check each alias and put into a set
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        this.aliasesSet = new HashSet<String>();
137bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (aliases != null) {
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            for (int i = 0; i < aliases.length; i++) {
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                checkCharsetName(aliases[i]);
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                this.aliasesSet.add(aliases[i]);
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks whether a character is a special character that can be used in
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * charset names, other than letters and digits.
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static boolean isSpecial(char c) {
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return ('-' == c || '.' == c || ':' == c || '_' == c);
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks whether a character is a letter (ascii) which are defined in the
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * spec.
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static boolean isLetter(char c) {
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks whether a character is a digit (ascii) which are defined in the
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * spec.
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static boolean isDigit(char c) {
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return ('0' <= c && c <= '9');
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Checks whether a given string is a legal charset name. The argument name
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * should not be null.
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static void checkCharsetName(String name) {
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // An empty string is illegal charset name
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (name.length() == 0) {
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalCharsetNameException(name);
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // The first character must be a letter or a digit
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // This is related to HARMONY-68 (won't fix)
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // char first = name.charAt(0);
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // if (!isLetter(first) && !isDigit(first)) {
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // throw new IllegalCharsetNameException(name);
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // }
184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Check the remaining characters
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length = name.length();
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i = 0; i < length; i++) {
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            char c = name.charAt(i);
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!isLetter(c) && !isDigit(c) && !isSpecial(c)) {
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                throw new IllegalCharsetNameException(name);
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Use privileged code to get the context class loader.
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static ClassLoader getContextClassLoader() {
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        final Thread t = Thread.currentThread();
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return AccessController
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .doPrivileged(new PrivilegedAction<ClassLoader>() {
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    public ClassLoader run() {
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        return t.getContextClassLoader();
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                });
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Use privileged code to get the system class loader.
209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static void getSystemClassLoader() {
211adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (null == systemClassLoader) {
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            systemClassLoader = AccessController
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    .doPrivileged(new PrivilegedAction<ClassLoader>() {
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        public ClassLoader run() {
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            return ClassLoader.getSystemClassLoader();
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    });
218adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Add the charsets supported by the given provider to the map.
223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
224bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    private static void addCharsets(CharsetProvider cp, Map<String, Charset> charsets) {
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Iterator<Charset> it = cp.charsets();
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        while (it.hasNext()) {
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Charset cs = it.next();
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Only new charsets will be added
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!charsets.containsKey(cs.name())) {
230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                charsets.put(cs.name(), cs);
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Trim comment string, and then trim white spaces.
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static String trimClassName(String name) {
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String trimedName = name;
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int index = name.indexOf(PROVIDER_CONFIGURATION_FILE_COMMENT);
241adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Trim comments
242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (index != -1) {
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            trimedName = name.substring(0, index);
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return trimedName.trim();
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Read a configuration file and add the charsets supported by the providers
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * specified by this configuration file to the map.
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static void loadConfiguredCharsets(URL configFile,
253bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            ClassLoader contextClassLoader, Map<String, Charset> charsets) {
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        BufferedReader reader = null;
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
256adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            InputStream is = configFile.openStream();
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Read each line for charset provider class names
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            reader = new BufferedReader(new InputStreamReader(is,
259b748a9b827665a8b19d60af4b419503b45e74329Elliott Hughes                    PROVIDER_CONFIGURATION_FILE_ENCODING));
260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String providerClassName = reader.readLine();
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (null != providerClassName) {
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                providerClassName = trimClassName(providerClassName);
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Skip comments and blank lines
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (providerClassName.length() > 0) { // Non empty string
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Load the charset provider
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Object cp = null;
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        Class<?> c = Class.forName(providerClassName, true,
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                contextClassLoader);
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        cp = c.newInstance();
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } catch (Exception ex) {
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // try to use system classloader when context
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // classloader failed to load config file.
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        try {
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            getSystemClassLoader();
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            Class<?> c = Class.forName(providerClassName, true,
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    systemClassLoader);
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            cp = c.newInstance();
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        } catch (Exception e) {
280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            throw new Error(e.getMessage(), e);
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Put the charsets supported by this provider into the map
284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    addCharsets((CharsetProvider) cp, charsets);
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Read the next line of the config file
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                providerClassName = reader.readLine();
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException ex) {
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Can't read this configuration file, ignore
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (null != reader) {
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    reader.close();
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (IOException ex) {
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Ignore closing exception
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
303adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a map of all available charsets supported by the runtime.
304adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
305adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The returned map contains mappings from canonical names to corresponding
306eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * instances of <code>Charset</code>. The canonical names can be considered
307eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * as case-insensitive.
308eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an unmodifiable map of all available charsets supported by the
310eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *         runtime
311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @SuppressWarnings("unchecked")
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static SortedMap<String, Charset> availableCharsets() {
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Initialize the built-in charsets map cache if necessary
315bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (_builtInCharsets == null) {
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            synchronized (Charset.class) {
317bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                if (_builtInCharsets == null) {
318bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                    _builtInCharsets = _builtInProvider.initAvailableCharsets();
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
323bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        // Start with the built-in charsets...
324bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        SortedMap<String, Charset> charsets = new TreeMap<String, Charset>(_builtInCharsets);
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
326bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        // Add all charsets provided by charset providers...
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        ClassLoader contextClassLoader = getContextClassLoader();
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Enumeration<URL> e = null;
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
330bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            if (contextClassLoader != null) {
331bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                e = contextClassLoader.getResources(PROVIDER_CONFIGURATION_FILE_NAME);
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                getSystemClassLoader();
334bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                e = systemClassLoader.getResources(PROVIDER_CONFIGURATION_FILE_NAME);
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Examine each configuration file
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (e.hasMoreElements()) {
338bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                loadConfiguredCharsets(e.nextElement(), contextClassLoader, charsets);
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException ex) {
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Unexpected ClassLoader exception, ignore
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return Collections.unmodifiableSortedMap(charsets);
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Read a configuration file and try to find the desired charset among those
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * which are supported by the providers specified in this configuration
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * file.
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static Charset searchConfiguredCharsets(String charsetName,
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            ClassLoader contextClassLoader, URL configFile) {
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        BufferedReader reader = null;
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            InputStream is = configFile.openStream();
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Read each line for charset provider class names
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            reader = new BufferedReader(new InputStreamReader(is,
358b748a9b827665a8b19d60af4b419503b45e74329Elliott Hughes                    PROVIDER_CONFIGURATION_FILE_ENCODING));
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            String providerClassName = reader.readLine();
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            while (null != providerClassName) {
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                providerClassName = trimClassName(providerClassName);
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (providerClassName.length() > 0) { // Non empty string
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Load the charset provider
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    Object cp = null;
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        Class<?> c = Class.forName(providerClassName, true,
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                contextClassLoader);
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        cp = c.newInstance();
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } catch (Exception ex) {
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // try to use system classloader when context
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // classloader failed to load config file.
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        try {
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            getSystemClassLoader();
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            Class<?> c = Class.forName(providerClassName, true,
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    systemClassLoader);
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            cp = c.newInstance();
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        } catch (SecurityException e) {
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            // BEGIN android-changed
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            // ignore
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            // END android-changed
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        } catch (Exception e) {
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            throw new Error(e.getMessage(), e);
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // BEGIN android-changed
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    if (cp != null) {
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        // Try to get the desired charset from this provider
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        Charset cs = ((CharsetProvider) cp)
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                .charsetForName(charsetName);
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (null != cs) {
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            return cs;
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // END android-changed
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Read the next line of the config file
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                providerClassName = reader.readLine();
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (IOException ex) {
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Can't read this configuration file
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } finally {
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            try {
405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                if (null != reader) {
406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    reader.close();
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } catch (IOException ex) {
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // Ignore closing exception
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
415eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * Gets a <code>Charset</code> instance for the specified charset name. If
416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * the charset is not supported, returns null instead of throwing an
417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * exception.
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
419eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private synchronized static Charset forNameInternal(String charsetName)
420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throws IllegalCharsetNameException {
421eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
422bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        Charset cs = lookupCachedOrBuiltInCharset(charsetName);
423bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (cs != null || inForNameInternal) {
424eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            return cs;
425eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        }
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
427eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        // collect all charsets provided by charset providers
428eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        try {
429bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            Enumeration<URL> e = null;
430bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            ClassLoader contextClassLoader = getContextClassLoader();
431bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            if (contextClassLoader != null) {
432bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                e = contextClassLoader.getResources(PROVIDER_CONFIGURATION_FILE_NAME);
433eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            } else {
434eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                getSystemClassLoader();
435eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                if (systemClassLoader == null) {
436eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    // Non available during class library start-up phase
437bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                    return null;
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                } else {
439bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                    e = systemClassLoader.getResources(PROVIDER_CONFIGURATION_FILE_NAME);
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
441eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            }
442eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
443eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            // examine each configuration file
444eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            while (e.hasMoreElements()) {
445bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                inForNameInternal = true;
446bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                cs = searchConfiguredCharsets(charsetName, contextClassLoader, e.nextElement());
447bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                inForNameInternal = false;
448bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                if (cs != null) {
449eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    cacheCharset(cs);
450eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    return cs;
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
453eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        } catch (IOException ex) {
454eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            // Unexpected ClassLoader exception, ignore
455eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        } finally {
456bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            inForNameInternal = false;
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return null;
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
461bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    private synchronized static Charset lookupCachedOrBuiltInCharset(String charsetName) {
462bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        Charset cs = cachedCharsetTable.get(charsetName);
463bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (cs != null) {
464bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            return cs;
465bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        }
466bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (charsetName == null) {
467bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            throw new IllegalArgumentException();
468bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        }
469bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        checkCharsetName(charsetName);
470bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        cs = _builtInProvider.charsetForName(charsetName);
471bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (cs != null) {
472bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            cacheCharset(cs);
473bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        }
474bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        return cs;
475bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    }
476bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * save charset into cachedCharsetTable
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
480bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes    private synchronized static void cacheCharset(Charset cs) {
481bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        // Cache the Charset by its canonical name...
482bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        String canonicalName = cs.name();
483bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (!cachedCharsetTable.containsKey(canonicalName)) {
484bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            cachedCharsetTable.put(canonicalName, cs);
485eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        }
486bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        // And all its aliases...
487bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        for (String alias : cs.aliasesSet) {
488bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes            if (!cachedCharsetTable.containsKey(alias)) {
489bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes                cachedCharsetTable.put(alias, cs);
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
491adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a <code>Charset</code> instance for the specified charset name.
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
497adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param charsetName
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the canonical name of the charset or an alias.
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a <code>Charset</code> instance for the specified charset name.
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalCharsetNameException
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified charset name is illegal.
502adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws UnsupportedCharsetException
503adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the desired charset is not supported by this runtime.
504adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
505eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    public static Charset forName(String charsetName) {
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Charset c = forNameInternal(charsetName);
507bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        if (c == null) {
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnsupportedCharsetException(charsetName);
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return c;
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Determines whether the specified charset is supported by this runtime.
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
516adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param charsetName
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the name of the charset.
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if the specified charset is supported, otherwise false.
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalCharsetNameException
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the specified charset name is illegal.
521adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
522eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    public static synchronized boolean isSupported(String charsetName) {
523bcf7c66e617ad0c33bb320184bb2401def517342Elliott Hughes        return forNameInternal(charsetName) != null;
524adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
525adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
526adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Determines whether this charset is a super set of the given charset.
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param charset
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            a given charset.
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if this charset is a super set of the given charset,
532adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         false if it's unknown or this charset is not a superset of
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         the given charset.
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public abstract boolean contains(Charset charset);
536adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
537adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
538adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a new instance of an encoder for this charset.
539adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
540adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a new instance of an encoder for this charset.
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public abstract CharsetEncoder newEncoder();
543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a new instance of a decoder for this charset.
546adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
547adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a new instance of a decoder for this charset.
548adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
549adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public abstract CharsetDecoder newDecoder();
550adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the canonical name of this charset.
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
554adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this charset's name in canonical form.
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final String name() {
557adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.canonicalName;
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the set of this charset's aliases.
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
563adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an unmodifiable set of this charset's aliases.
564adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final Set<String> aliases() {
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return Collections.unmodifiableSet(this.aliasesSet);
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
568adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
569adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
570adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the name of this charset for the default locale.
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
572eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * <p>The default implementation returns the canonical name of this charset.
573eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * Subclasses may return a localized display name.
574eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the name of this charset for the default locale.
576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String displayName() {
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.canonicalName;
579adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
580adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
581adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
582adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the name of this charset for the specified locale.
583eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
584eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * <p>The default implementation returns the canonical name of this charset.
585eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * Subclasses may return a localized display name.
586eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param l
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            a certain locale
589eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * @return the name of this charset for the specified locale
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String displayName(Locale l) {
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.canonicalName;
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
594adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates whether this charset is known to be registered in the IANA
597adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Charset Registry.
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if the charset is known to be registered, otherwise returns
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         false.
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final boolean isRegistered() {
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return !canonicalName.startsWith("x-") //$NON-NLS-1$
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                && !canonicalName.startsWith("X-"); //$NON-NLS-1$
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns true if this charset supports encoding, false otherwise.
609adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
610adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if this charset supports encoding, false otherwise.
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canEncode() {
613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return true;
614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Encodes the content of the give character buffer and outputs to a byte
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * buffer that is to be returned.
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The default action in case of encoding errors is
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CodingErrorAction.REPLACE</code>.
622eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param buffer
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the character buffer containing the content to be encoded.
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the result of the encoding.
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
627eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    public final ByteBuffer encode(CharBuffer buffer) {
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
629eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            return this.newEncoder()
630eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    .onMalformedInput(CodingErrorAction.REPLACE)
631eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    .onUnmappableCharacter(CodingErrorAction.REPLACE).encode(
632eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                            buffer);
633eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (CharacterCodingException ex) {
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new Error(ex.getMessage(), ex);
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Encodes a string and outputs to a byte buffer that is to be returned.
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The default action in case of encoding errors is
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CodingErrorAction.REPLACE</code>.
644eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     *
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param s
646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the string to be encoded.
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the result of the encoding.
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final ByteBuffer encode(String s) {
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return encode(CharBuffer.wrap(s));
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Decodes the content of the specified byte buffer and writes it to a
655adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * character buffer that is to be returned.
656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The default action in case of decoding errors is
658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <code>CodingErrorAction.REPLACE</code>.
659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param buffer
661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the byte buffer containing the content to be decoded.
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a character buffer containing the output of the decoding.
663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final CharBuffer decode(ByteBuffer buffer) {
665eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
667eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            return this.newDecoder()
668eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    .onMalformedInput(CodingErrorAction.REPLACE)
669eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    .onUnmappableCharacter(CodingErrorAction.REPLACE).decode(
670eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                            buffer);
671eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (CharacterCodingException ex) {
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new Error(ex.getMessage(), ex);
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -------------------------------------------------------------------
679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Methods implementing parent interface Comparable
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -------------------------------------------------------------------
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Compares this charset with the given charset. This comparation is
685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * based on the case insensitive canonical names of the charsets.
686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param charset
688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given object to be compared with.
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a negative integer if less than the given object, a positive
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         integer if larger than it, or 0 if equal to it.
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int compareTo(Charset charset) {
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.canonicalName.compareToIgnoreCase(charset.canonicalName);
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
695adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
696adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /*
697adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -------------------------------------------------------------------
698adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Methods overriding parent class Object
699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * -------------------------------------------------------------------
700adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Determines whether this charset equals to the given object. They are
704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * considered to be equal if they have the same canonical name.
705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param obj
707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the given object to be compared with.
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return true if they have the same canonical name, otherwise false.
709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final boolean equals(Object obj) {
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (obj instanceof Charset) {
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            Charset that = (Charset) obj;
714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return this.canonicalName.equals(that.canonicalName);
715adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return false;
717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the hash code of this charset.
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the hash code of this charset.
723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final int hashCode() {
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this.canonicalName.hashCode();
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
730adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a string representation of this charset. Usually this contains the
731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * canonical name of the charset.
732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a string representation of this charset.
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
735adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public final String toString() {
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return "Charset[" + this.canonicalName + "]"; //$NON-NLS-1$//$NON-NLS-2$
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the system default charset from the virtual machine.
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *
743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the default charset.
744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static Charset defaultCharset() {
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Charset defaultCharset = null;
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String encoding = AccessController
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                .doPrivileged(new PrivilegedAction<String>() {
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    public String run() {
750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        return System.getProperty("file.encoding"); //$NON-NLS-1$
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                });
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            defaultCharset = Charset.forName(encoding);
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (UnsupportedCharsetException e) {
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            defaultCharset = Charset.forName("UTF-8"); //$NON-NLS-1$
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return defaultCharset;
759adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
761