1/*
2 * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.nio.cs;
27
28import java.nio.charset.Charset;
29import java.nio.charset.spi.CharsetProvider;
30import java.util.Iterator;
31import java.util.Map;
32
33
34/**
35 * Abstract base class for fast charset providers.
36 *
37 * @author Mark Reinhold
38 */
39
40public class FastCharsetProvider
41    extends CharsetProvider
42{
43
44    // Maps canonical names to class names
45    private Map<String,String> classMap;
46
47    // Maps alias names to canonical names
48    private Map<String,String> aliasMap;
49
50    // Maps canonical names to cached instances
51    private Map<String,Charset> cache;
52
53    private String packagePrefix;
54
55    protected FastCharsetProvider(String pp,
56                                  Map<String,String> am,
57                                  Map<String,String> cm,
58                                  Map<String,Charset> c)
59    {
60        packagePrefix = pp;
61        aliasMap = am;
62        classMap = cm;
63        cache = c;
64    }
65
66    private String canonicalize(String csn) {
67        String acn = aliasMap.get(csn);
68        return (acn != null) ? acn : csn;
69    }
70
71    // Private ASCII-only version, optimized for interpretation during startup
72    //
73    private static String toLower(String s) {
74        int n = s.length();
75        boolean allLower = true;
76        for (int i = 0; i < n; i++) {
77            int c = s.charAt(i);
78            if (((c - 'A') | ('Z' - c)) >= 0) {
79                allLower = false;
80                break;
81            }
82        }
83        if (allLower)
84            return s;
85        char[] ca = new char[n];
86        for (int i = 0; i < n; i++) {
87            int c = s.charAt(i);
88            if (((c - 'A') | ('Z' - c)) >= 0)
89                ca[i] = (char)(c + 0x20);
90            else
91                ca[i] = (char)c;
92        }
93        return new String(ca);
94    }
95
96    private Charset lookup(String charsetName) {
97
98        String csn = canonicalize(toLower(charsetName));
99
100        // Check cache first
101        Charset cs = cache.get(csn);
102        if (cs != null)
103            return cs;
104
105        // Do we even support this charset?
106        String cln = classMap.get(csn);
107        if (cln == null)
108            return null;
109
110        if (cln.equals("US_ASCII")) {
111            cs = new US_ASCII();
112            cache.put(csn, cs);
113            return cs;
114        }
115
116        // Instantiate the charset and cache it
117        try {
118            @SuppressWarnings("deprecation")
119            Object o= Class.forName(packagePrefix + "." + cln,
120                                    true,
121                                    this.getClass().getClassLoader()).newInstance();
122            cs = (Charset)o;
123            cache.put(csn, cs);
124            return cs;
125        } catch (ClassNotFoundException |
126                 IllegalAccessException |
127                 InstantiationException x) {
128            return null;
129        }
130    }
131
132    public final Charset charsetForName(String charsetName) {
133        synchronized (this) {
134            return lookup(canonicalize(charsetName));
135        }
136    }
137
138    public final Iterator<Charset> charsets() {
139
140        return new Iterator<Charset>() {
141
142                Iterator<String> i = classMap.keySet().iterator();
143
144                public boolean hasNext() {
145                    return i.hasNext();
146                }
147
148                public Charset next() {
149                    String csn = i.next();
150                    return lookup(csn);
151                }
152
153                public void remove() {
154                    throw new UnsupportedOperationException();
155                }
156
157            };
158
159    }
160
161}
162