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 
  26 package sun.nio.cs;
  27 
  28 import java.nio.charset.Charset;
  29 import java.nio.charset.spi.CharsetProvider;
  30 import java.util.Iterator;
  31 import java.util.Map;
  32 
  33 
  34 /**
  35  * Abstract base class for fast charset providers.
  36  *
  37  * @author Mark Reinhold
  38  */
  39 
  40 public 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             Class<?> c = Class.forName(packagePrefix + "." + cln,
 119                                     true,
 120                                     this.getClass().getClassLoader());
 121             cs = (Charset)c.newInstance();
 122             cache.put(csn, cs);
 123             return cs;
 124         } catch (ClassNotFoundException |
 125                  IllegalAccessException |
 126                  InstantiationException x) {
 127             return null;
 128         }
 129     }
 130 
 131     public final Charset charsetForName(String charsetName) {
 132         synchronized (this) {
 133             return lookup(canonicalize(charsetName));
 134         }
 135     }
 136 
 137     public final Iterator<Charset> charsets() {
 138 
 139         return new Iterator<Charset>() {
 140 
 141                 Iterator<String> i = classMap.keySet().iterator();
 142 
 143                 public boolean hasNext() {
 144                     return i.hasNext();
 145                 }
 146 
 147                 public Charset next() {
 148                     String csn = i.next();
 149                     return lookup(csn);
 150                 }
 151 
 152                 public void remove() {
 153                     throw new UnsupportedOperationException();
 154                 }
 155 
 156             };
 157 
 158     }
 159 
 160 }