286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 2000-2002,2004,2005 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xml.internal.serialize;
286N/A
286N/Aimport java.io.OutputStream;
286N/Aimport java.io.OutputStreamWriter;
286N/Aimport java.io.UnsupportedEncodingException;
286N/Aimport java.io.Writer;
286N/Aimport com.sun.org.apache.xerces.internal.util.EncodingMap;
286N/A
286N/A/**
286N/A * This class represents an encoding.
286N/A *
286N/A * @version $Id: EncodingInfo.java,v 1.6 2007/10/18 03:39:08 joehw Exp $
286N/A */
286N/Apublic class EncodingInfo {
286N/A
286N/A // An array to hold the argument for a method of Charset, CharsetEncoder or CharToByteConverter.
286N/A private Object [] fArgsForMethod = null;
286N/A
286N/A // name of encoding as registered with IANA;
286N/A // preferably a MIME name, but aliases are fine too.
286N/A String ianaName;
286N/A String javaName;
286N/A int lastPrintable;
286N/A
286N/A // The CharsetEncoder with which we test unusual characters.
286N/A Object fCharsetEncoder = null;
286N/A
286N/A // The CharToByteConverter with which we test unusual characters.
286N/A Object fCharToByteConverter = null;
286N/A
286N/A // Is the converter null because it can't be instantiated
286N/A // for some reason (perhaps we're running with insufficient authority as
286N/A // an applet?
286N/A boolean fHaveTriedCToB = false;
286N/A
286N/A // Is the charset encoder usable or available.
286N/A boolean fHaveTriedCharsetEncoder = false;
286N/A
286N/A /**
286N/A * Creates new <code>EncodingInfo</code> instance.
286N/A */
286N/A public EncodingInfo(String ianaName, String javaName, int lastPrintable) {
286N/A this.ianaName = ianaName;
286N/A this.javaName = EncodingMap.getIANA2JavaMapping(ianaName);
286N/A this.lastPrintable = lastPrintable;
286N/A }
286N/A
286N/A /**
286N/A * Returns a MIME charset name of this encoding.
286N/A */
286N/A public String getIANAName() {
286N/A return this.ianaName;
286N/A }
286N/A
286N/A /**
286N/A * Returns a writer for this encoding based on
286N/A * an output stream.
286N/A *
286N/A * @return A suitable writer
286N/A * @exception UnsupportedEncodingException There is no convertor
286N/A * to support this encoding
286N/A */
286N/A public Writer getWriter(OutputStream output)
286N/A throws UnsupportedEncodingException {
286N/A // this should always be true!
286N/A if (javaName != null)
286N/A return new OutputStreamWriter(output, javaName);
286N/A javaName = EncodingMap.getIANA2JavaMapping(ianaName);
286N/A if(javaName == null)
286N/A // use UTF-8 as preferred encoding
286N/A return new OutputStreamWriter(output, "UTF8");
286N/A return new OutputStreamWriter(output, javaName);
286N/A }
286N/A
286N/A /**
286N/A * Checks whether the specified character is printable or not in this encoding.
286N/A *
286N/A * @param ch a code point (0-0x10ffff)
286N/A */
286N/A public boolean isPrintable(char ch) {
286N/A if (ch <= this.lastPrintable) {
286N/A return true;
286N/A }
286N/A return isPrintable0(ch);
286N/A }
286N/A
286N/A /**
286N/A * Checks whether the specified character is printable or not in this encoding.
286N/A * This method accomplishes this using a java.nio.CharsetEncoder. If NIO isn't
286N/A * available it will attempt use a sun.io.CharToByteConverter.
286N/A *
286N/A * @param ch a code point (0-0x10ffff)
286N/A */
286N/A private boolean isPrintable0(char ch) {
286N/A
286N/A // Attempt to get a CharsetEncoder for this encoding.
286N/A if (fCharsetEncoder == null && CharsetMethods.fgNIOCharsetAvailable && !fHaveTriedCharsetEncoder) {
286N/A if (fArgsForMethod == null) {
286N/A fArgsForMethod = new Object [1];
286N/A }
286N/A // try and create the CharsetEncoder
286N/A try {
286N/A fArgsForMethod[0] = javaName;
286N/A Object charset = CharsetMethods.fgCharsetForNameMethod.invoke(null, fArgsForMethod);
286N/A if (((Boolean) CharsetMethods.fgCharsetCanEncodeMethod.invoke(charset, (Object[]) null)).booleanValue()) {
286N/A fCharsetEncoder = CharsetMethods.fgCharsetNewEncoderMethod.invoke(charset, (Object[]) null);
286N/A }
286N/A // This charset cannot be used for encoding, don't try it again...
286N/A else {
286N/A fHaveTriedCharsetEncoder = true;
286N/A }
286N/A }
286N/A catch (Exception e) {
286N/A // don't try it again...
286N/A fHaveTriedCharsetEncoder = true;
286N/A }
286N/A }
286N/A // Attempt to use the CharsetEncoder to determine whether the character is printable.
286N/A if (fCharsetEncoder != null) {
286N/A try {
286N/A fArgsForMethod[0] = new Character(ch);
286N/A return ((Boolean) CharsetMethods.fgCharsetEncoderCanEncodeMethod.invoke(fCharsetEncoder, fArgsForMethod)).booleanValue();
286N/A }
286N/A catch (Exception e) {
286N/A // obviously can't use this charset encoder; possibly a JDK bug
286N/A fCharsetEncoder = null;
286N/A fHaveTriedCharsetEncoder = false;
286N/A }
286N/A }
286N/A
286N/A // As a last resort try to use a sun.io.CharToByteConverter to
286N/A // determine whether this character is printable. We will always
286N/A // reach here on JDK 1.3 or below.
286N/A if (fCharToByteConverter == null) {
286N/A if (fHaveTriedCToB || !CharToByteConverterMethods.fgConvertersAvailable) {
286N/A // forget it; nothing we can do...
286N/A return false;
286N/A }
286N/A if (fArgsForMethod == null) {
286N/A fArgsForMethod = new Object [1];
286N/A }
286N/A // try and create the CharToByteConverter
286N/A try {
286N/A fArgsForMethod[0] = javaName;
286N/A fCharToByteConverter = CharToByteConverterMethods.fgGetConverterMethod.invoke(null, fArgsForMethod);
286N/A }
286N/A catch (Exception e) {
286N/A // don't try it again...
286N/A fHaveTriedCToB = true;
286N/A return false;
286N/A }
286N/A }
286N/A try {
286N/A fArgsForMethod[0] = new Character(ch);
286N/A return ((Boolean) CharToByteConverterMethods.fgCanConvertMethod.invoke(fCharToByteConverter, fArgsForMethod)).booleanValue();
286N/A }
286N/A catch (Exception e) {
286N/A // obviously can't use this converter; probably some kind of
286N/A // security restriction
286N/A fCharToByteConverter = null;
286N/A fHaveTriedCToB = false;
286N/A return false;
286N/A }
286N/A }
286N/A
286N/A // is this an encoding name recognized by this JDK?
286N/A // if not, will throw UnsupportedEncodingException
286N/A public static void testJavaEncodingName(String name) throws UnsupportedEncodingException {
286N/A final byte [] bTest = {(byte)'v', (byte)'a', (byte)'l', (byte)'i', (byte)'d'};
286N/A String s = new String(bTest, name);
286N/A }
286N/A
286N/A /**
286N/A * Holder of methods from java.nio.charset.Charset and java.nio.charset.CharsetEncoder.
286N/A */
286N/A static class CharsetMethods {
286N/A
286N/A // Method: java.nio.charset.Charset.forName(java.lang.String)
286N/A private static java.lang.reflect.Method fgCharsetForNameMethod = null;
286N/A
286N/A // Method: java.nio.charset.Charset.canEncode()
286N/A private static java.lang.reflect.Method fgCharsetCanEncodeMethod = null;
286N/A
286N/A // Method: java.nio.charset.Charset.newEncoder()
286N/A private static java.lang.reflect.Method fgCharsetNewEncoderMethod = null;
286N/A
286N/A // Method: java.nio.charset.CharsetEncoder.canEncode(char)
286N/A private static java.lang.reflect.Method fgCharsetEncoderCanEncodeMethod = null;
286N/A
286N/A // Flag indicating whether or not java.nio.charset.* is available.
286N/A private static boolean fgNIOCharsetAvailable = false;
286N/A
286N/A private CharsetMethods() {}
286N/A
286N/A // Attempt to get methods for Charset and CharsetEncoder on class initialization.
286N/A static {
286N/A try {
286N/A Class charsetClass = Class.forName("java.nio.charset.Charset");
286N/A Class charsetEncoderClass = Class.forName("java.nio.charset.CharsetEncoder");
286N/A fgCharsetForNameMethod = charsetClass.getMethod("forName", new Class [] {String.class});
286N/A fgCharsetCanEncodeMethod = charsetClass.getMethod("canEncode", new Class [] {});
286N/A fgCharsetNewEncoderMethod = charsetClass.getMethod("newEncoder", new Class [] {});
286N/A fgCharsetEncoderCanEncodeMethod = charsetEncoderClass.getMethod("canEncode", new Class [] {Character.TYPE});
286N/A fgNIOCharsetAvailable = true;
286N/A }
286N/A // ClassNotFoundException, NoSuchMethodException or SecurityException
286N/A // Whatever the case, we cannot use java.nio.charset.*.
286N/A catch (Exception exc) {
286N/A fgCharsetForNameMethod = null;
286N/A fgCharsetCanEncodeMethod = null;
286N/A fgCharsetEncoderCanEncodeMethod = null;
286N/A fgCharsetNewEncoderMethod = null;
286N/A fgNIOCharsetAvailable = false;
286N/A }
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Holder of methods from sun.io.CharToByteConverter.
286N/A */
286N/A static class CharToByteConverterMethods {
286N/A
286N/A // Method: sun.io.CharToByteConverter.getConverter(java.lang.String)
286N/A private static java.lang.reflect.Method fgGetConverterMethod = null;
286N/A
286N/A // Method: sun.io.CharToByteConverter.canConvert(char)
286N/A private static java.lang.reflect.Method fgCanConvertMethod = null;
286N/A
286N/A // Flag indicating whether or not sun.io.CharToByteConverter is available.
286N/A private static boolean fgConvertersAvailable = false;
286N/A
286N/A private CharToByteConverterMethods() {}
286N/A
286N/A // Attempt to get methods for char to byte converter on class initialization.
286N/A static {
286N/A try {
286N/A Class clazz = Class.forName("sun.io.CharToByteConverter");
286N/A fgGetConverterMethod = clazz.getMethod("getConverter", new Class [] {String.class});
286N/A fgCanConvertMethod = clazz.getMethod("canConvert", new Class [] {Character.TYPE});
286N/A fgConvertersAvailable = true;
286N/A }
286N/A // ClassNotFoundException, NoSuchMethodException or SecurityException
286N/A // Whatever the case, we cannot use sun.io.CharToByteConverter.
286N/A catch (Exception exc) {
286N/A fgGetConverterMethod = null;
286N/A fgCanConvertMethod = null;
286N/A fgConvertersAvailable = false;
286N/A }
286N/A }
286N/A }
286N/A}