0N/A/*
3261N/A * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.io;
0N/A
0N/Aimport java.io.UnsupportedEncodingException;
0N/Aimport java.lang.ref.SoftReference;
0N/Aimport java.util.Properties;
0N/A
0N/A/**
0N/A * Package-private utility class that caches the default converter classes and
0N/A * provides other logic common to both the ByteToCharConverter and
0N/A * CharToByteConverter classes.
0N/A *
0N/A * @author Mark Reinhold
0N/A * @since 1.2
0N/A *
0N/A * @deprecated Replaced by {@link java.nio.charset}. THIS API WILL BE
0N/A * REMOVED IN J2SE 1.6.
0N/A */
0N/A@Deprecated
0N/Apublic class Converters {
0N/A
0N/A private Converters() { } /* To prevent instantiation */
0N/A
0N/A /* Lock for all static fields in this class */
0N/A private static Object lock = Converters.class;
0N/A
0N/A /* Cached values of system properties */
0N/A private static String converterPackageName = null; /* file.encoding.pkg */
0N/A private static String defaultEncoding = null; /* file.encoding */
0N/A
0N/A /* Converter type constants and names */
0N/A public static final int BYTE_TO_CHAR = 0;
0N/A public static final int CHAR_TO_BYTE = 1;
0N/A private static final String[] converterPrefix = { "ByteToChar",
0N/A "CharToByte" };
0N/A
0N/A
0N/A // -- Converter class cache --
0N/A
0N/A private static final int CACHE_SIZE = 3;
0N/A
0N/A /* For the default charset, whatever it turns out to be */
0N/A private static final Object DEFAULT_NAME = new Object();
0N/A
0N/A /* Cached converter classes, CACHE_SIZE per converter type. Each cache
0N/A * entry is a soft reference to a two-object array; the first element of
0N/A * the array is the converter class, the second is an object (typically a
0N/A * string) representing the encoding name that was used to request the
0N/A * converter, e.g.,
0N/A *
0N/A * ((Object[])classCache[CHAR_TO_BYTE][i].get())[0]
0N/A *
0N/A * will be a CharToByteConverter and
0N/A *
0N/A * ((Object[])classCache[CHAR_TO_BYTE][i].get())[1]
0N/A *
0N/A * will be the string encoding name used to request it, assuming that cache
0N/A * entry i is valid.
0N/A *
0N/A * Ordinarily we'd do this with a private static utility class, but since
0N/A * this code can be involved in the startup sequence it's important to keep
0N/A * the footprint down.
0N/A */
2116N/A @SuppressWarnings("unchecked")
2116N/A private static SoftReference<Object[]>[][] classCache
2116N/A = (SoftReference<Object[]>[][]) new SoftReference<?>[][] {
2116N/A new SoftReference<?>[CACHE_SIZE],
2116N/A new SoftReference<?>[CACHE_SIZE]
0N/A };
0N/A
0N/A private static void moveToFront(Object[] oa, int i) {
0N/A Object ob = oa[i];
0N/A for (int j = i; j > 0; j--)
0N/A oa[j] = oa[j - 1];
0N/A oa[0] = ob;
0N/A }
0N/A
2116N/A private static Class<?> cache(int type, Object encoding) {
2116N/A SoftReference<Object[]>[] srs = classCache[type];
0N/A for (int i = 0; i < CACHE_SIZE; i++) {
2116N/A SoftReference<Object[]> sr = srs[i];
0N/A if (sr == null)
0N/A continue;
2116N/A Object[] oa = sr.get();
0N/A if (oa == null) {
0N/A srs[i] = null;
0N/A continue;
0N/A }
0N/A if (oa[1].equals(encoding)) {
0N/A moveToFront(srs, i);
2116N/A return (Class<?>)oa[0];
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
2116N/A private static Class<?> cache(int type, Object encoding, Class<?> c) {
2116N/A SoftReference<Object[]>[] srs = classCache[type];
3323N/A srs[CACHE_SIZE - 1] = new SoftReference<>(new Object[] { c, encoding });
0N/A moveToFront(srs, CACHE_SIZE - 1);
0N/A return c;
0N/A }
0N/A
0N/A /* Used to avoid doing expensive charset lookups for charsets that are not
0N/A * yet directly supported by NIO.
0N/A */
0N/A public static boolean isCached(int type, String encoding) {
0N/A synchronized (lock) {
2116N/A SoftReference<Object[]>[] srs = classCache[type];
0N/A for (int i = 0; i < CACHE_SIZE; i++) {
2116N/A SoftReference<Object[]> sr = srs[i];
0N/A if (sr == null)
0N/A continue;
2116N/A Object[] oa = sr.get();
0N/A if (oa == null) {
0N/A srs[i] = null;
0N/A continue;
0N/A }
0N/A if (oa[1].equals(encoding))
0N/A return true;
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A
0N/A
0N/A /** Get the name of the converter package */
0N/A private static String getConverterPackageName() {
0N/A String cp = converterPackageName;
0N/A if (cp != null) return cp;
2116N/A java.security.PrivilegedAction<String> pa =
0N/A new sun.security.action.GetPropertyAction("file.encoding.pkg");
2116N/A cp = java.security.AccessController.doPrivileged(pa);
0N/A if (cp != null) {
0N/A /* Property is set, so take it as the true converter package */
0N/A converterPackageName = cp;
0N/A } else {
0N/A /* Fall back to sun.io */
0N/A cp = "sun.io";
0N/A }
0N/A return cp;
0N/A }
0N/A
0N/A public static String getDefaultEncodingName() {
0N/A synchronized (lock) {
0N/A if (defaultEncoding == null) {
2116N/A java.security.PrivilegedAction<String> pa =
0N/A new sun.security.action.GetPropertyAction("file.encoding");
2116N/A defaultEncoding = java.security.AccessController.doPrivileged(pa);
0N/A }
0N/A }
0N/A return defaultEncoding;
0N/A }
0N/A
0N/A public static void resetDefaultEncodingName() {
0N/A // This method should only be called during VM initialization.
0N/A if (sun.misc.VM.isBooted())
0N/A return;
0N/A
0N/A synchronized (lock) {
0N/A defaultEncoding = "ISO-8859-1";
0N/A Properties p = System.getProperties();
0N/A p.setProperty("file.encoding", defaultEncoding);
0N/A System.setProperties(p);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Get the class that implements the given type of converter for the named
0N/A * encoding, or throw an UnsupportedEncodingException if no such class can
0N/A * be found
0N/A */
2116N/A private static Class<?> getConverterClass(int type, String encoding)
0N/A throws UnsupportedEncodingException
0N/A {
0N/A String enc = null;
0N/A
0N/A /* "ISO8859_1" is the canonical name for the ISO-Latin-1 encoding.
0N/A Native code in the JDK commonly uses the alias "8859_1" instead of
0N/A "ISO8859_1". We hardwire this alias here in order to avoid loading
0N/A the full alias table just for this case. */
0N/A if (!encoding.equals("ISO8859_1")) {
0N/A if (encoding.equals("8859_1")) {
0N/A enc = "ISO8859_1";
0N/A /*
0N/A * On Solaris with nl_langinfo() called in GetJavaProperties():
0N/A *
0N/A * locale undefined -> NULL -> hardcoded default
0N/A * "C" locale -> "" -> hardcoded default (on 2.6)
0N/A * "C" locale -> "646" (on 2.7)
0N/A * "en_US" locale -> "ISO8859-1"
0N/A * "en_GB" locale -> "ISO8859-1" (on 2.7)
0N/A * "en_UK" locale -> "ISO8859-1" (on 2.6)
0N/A */
0N/A } else if (encoding.equals("ISO8859-1")) {
0N/A enc = "ISO8859_1";
0N/A } else if (encoding.equals("646")) {
0N/A enc = "ASCII";
0N/A } else {
0N/A enc = CharacterEncoding.aliasName(encoding);
0N/A }
0N/A }
0N/A if (enc == null) {
0N/A enc = encoding;
0N/A }
0N/A
0N/A try {
0N/A return Class.forName(getConverterPackageName()
0N/A + "." + converterPrefix[type] + enc);
0N/A } catch(ClassNotFoundException e) {
0N/A throw new UnsupportedEncodingException(enc);
0N/A }
0N/A
0N/A }
0N/A
0N/A /**
0N/A * Instantiate the given converter class, or throw an
0N/A * UnsupportedEncodingException if it cannot be instantiated
0N/A */
2116N/A private static Object newConverter(String enc, Class<?> c)
0N/A throws UnsupportedEncodingException
0N/A {
0N/A try {
0N/A return c.newInstance();
0N/A } catch(InstantiationException e) {
0N/A throw new UnsupportedEncodingException(enc);
0N/A } catch(IllegalAccessException e) {
0N/A throw new UnsupportedEncodingException(enc);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Create a converter object that implements the given type of converter
0N/A * for the given encoding, or throw an UnsupportedEncodingException if no
0N/A * appropriate converter class can be found and instantiated
0N/A */
0N/A static Object newConverter(int type, String enc)
0N/A throws UnsupportedEncodingException
0N/A {
2116N/A Class<?> c;
0N/A synchronized (lock) {
0N/A c = cache(type, enc);
0N/A if (c == null) {
0N/A c = getConverterClass(type, enc);
0N/A if (!c.getName().equals("sun.io.CharToByteUTF8"))
0N/A cache(type, enc, c);
0N/A }
0N/A }
0N/A return newConverter(enc, c);
0N/A }
0N/A
0N/A /**
0N/A * Find the class that implements the given type of converter for the
0N/A * default encoding. If the default encoding cannot be determined or is
0N/A * not yet defined, return a class that implements the fallback default
0N/A * encoding, which is just ISO 8859-1.
0N/A */
2116N/A private static Class<?> getDefaultConverterClass(int type) {
0N/A boolean fillCache = false;
2116N/A Class<?> c;
0N/A
0N/A /* First check the class cache */
0N/A c = cache(type, DEFAULT_NAME);
0N/A if (c != null)
0N/A return c;
0N/A
0N/A /* Determine the encoding name */
0N/A String enc = getDefaultEncodingName();
0N/A if (enc != null) {
0N/A /* file.encoding has been set, so cache the converter class */
0N/A fillCache = true;
0N/A } else {
0N/A /* file.encoding has not been set, so use a default encoding which
0N/A will not be cached */
0N/A enc = "ISO8859_1";
0N/A }
0N/A
0N/A /* We have an encoding name; try to find its class */
0N/A try {
0N/A c = getConverterClass(type, enc);
0N/A if (fillCache) {
0N/A cache(type, DEFAULT_NAME, c);
0N/A }
0N/A } catch (UnsupportedEncodingException x) {
0N/A /* Can't find the default class, so fall back to ISO 8859-1 */
0N/A try {
0N/A c = getConverterClass(type, "ISO8859_1");
0N/A } catch (UnsupportedEncodingException y) {
0N/A throw new InternalError("Cannot find default "
0N/A + converterPrefix[type]
0N/A + " converter class");
0N/A }
0N/A }
0N/A return c;
0N/A
0N/A }
0N/A
0N/A /**
0N/A * Create a converter object that implements the given type of converter
0N/A * for the default encoding, falling back to ISO 8859-1 if the default
0N/A * encoding cannot be determined.
0N/A */
0N/A static Object newDefaultConverter(int type) {
2116N/A Class<?> c;
0N/A synchronized (lock) {
0N/A c = getDefaultConverterClass(type);
0N/A }
0N/A try {
0N/A return newConverter("", c);
0N/A } catch (UnsupportedEncodingException x) {
0N/A throw new InternalError("Cannot instantiate default converter"
0N/A + " class " + c.getName());
0N/A }
0N/A }
0N/A
0N/A}