001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xml.serialize;
019:
020: import java.io.OutputStream;
021: import java.io.OutputStreamWriter;
022: import java.io.UnsupportedEncodingException;
023: import java.io.Writer;
024: import org.apache.xerces.util.EncodingMap;
025:
026: /**
027: * This class represents an encoding.
028: *
029: * @deprecated This class was deprecated in Xerces 2.9.0. It is recommended
030: * that new applications use the DOM Level 3 LSSerializer or JAXP's Transformation
031: * API for XML (TrAX) for serializing XML. See the Xerces documentation for more
032: * information.
033: * @version $Id: EncodingInfo.java 476047 2006-11-17 04:27:45Z mrglavas $
034: */
035: public class EncodingInfo {
036:
037: // An array to hold the argument for a method of Charset, CharsetEncoder or CharToByteConverter.
038: private Object[] fArgsForMethod = null;
039:
040: // name of encoding as registered with IANA;
041: // preferably a MIME name, but aliases are fine too.
042: String ianaName;
043: String javaName;
044: int lastPrintable;
045:
046: // The CharsetEncoder with which we test unusual characters.
047: Object fCharsetEncoder = null;
048:
049: // The CharToByteConverter with which we test unusual characters.
050: Object fCharToByteConverter = null;
051:
052: // Is the converter null because it can't be instantiated
053: // for some reason (perhaps we're running with insufficient authority as
054: // an applet?
055: boolean fHaveTriedCToB = false;
056:
057: // Is the charset encoder usable or available.
058: boolean fHaveTriedCharsetEncoder = false;
059:
060: /**
061: * Creates new <code>EncodingInfo</code> instance.
062: */
063: public EncodingInfo(String ianaName, String javaName,
064: int lastPrintable) {
065: this .ianaName = ianaName;
066: this .javaName = EncodingMap.getIANA2JavaMapping(ianaName);
067: this .lastPrintable = lastPrintable;
068: }
069:
070: /**
071: * Returns a MIME charset name of this encoding.
072: */
073: public String getIANAName() {
074: return this .ianaName;
075: }
076:
077: /**
078: * Returns a writer for this encoding based on
079: * an output stream.
080: *
081: * @return A suitable writer
082: * @exception UnsupportedEncodingException There is no convertor
083: * to support this encoding
084: */
085: public Writer getWriter(OutputStream output)
086: throws UnsupportedEncodingException {
087: // this should always be true!
088: if (javaName != null)
089: return new OutputStreamWriter(output, javaName);
090: javaName = EncodingMap.getIANA2JavaMapping(ianaName);
091: if (javaName == null)
092: // use UTF-8 as preferred encoding
093: return new OutputStreamWriter(output, "UTF8");
094: return new OutputStreamWriter(output, javaName);
095: }
096:
097: /**
098: * Checks whether the specified character is printable or not in this encoding.
099: *
100: * @param ch a code point (0-0x10ffff)
101: */
102: public boolean isPrintable(char ch) {
103: if (ch <= this .lastPrintable) {
104: return true;
105: }
106: return isPrintable0(ch);
107: }
108:
109: /**
110: * Checks whether the specified character is printable or not in this encoding.
111: * This method accomplishes this using a java.nio.CharsetEncoder. If NIO isn't
112: * available it will attempt use a sun.io.CharToByteConverter.
113: *
114: * @param ch a code point (0-0x10ffff)
115: */
116: private boolean isPrintable0(char ch) {
117:
118: // Attempt to get a CharsetEncoder for this encoding.
119: if (fCharsetEncoder == null
120: && CharsetMethods.fgNIOCharsetAvailable
121: && !fHaveTriedCharsetEncoder) {
122: if (fArgsForMethod == null) {
123: fArgsForMethod = new Object[1];
124: }
125: // try and create the CharsetEncoder
126: try {
127: fArgsForMethod[0] = javaName;
128: Object charset = CharsetMethods.fgCharsetForNameMethod
129: .invoke(null, fArgsForMethod);
130: if (((Boolean) CharsetMethods.fgCharsetCanEncodeMethod
131: .invoke(charset, (Object[]) null))
132: .booleanValue()) {
133: fCharsetEncoder = CharsetMethods.fgCharsetNewEncoderMethod
134: .invoke(charset, (Object[]) null);
135: }
136: // This charset cannot be used for encoding, don't try it again...
137: else {
138: fHaveTriedCharsetEncoder = true;
139: }
140: } catch (Exception e) {
141: // don't try it again...
142: fHaveTriedCharsetEncoder = true;
143: }
144: }
145: // Attempt to use the CharsetEncoder to determine whether the character is printable.
146: if (fCharsetEncoder != null) {
147: try {
148: fArgsForMethod[0] = new Character(ch);
149: return ((Boolean) CharsetMethods.fgCharsetEncoderCanEncodeMethod
150: .invoke(fCharsetEncoder, fArgsForMethod))
151: .booleanValue();
152: } catch (Exception e) {
153: // obviously can't use this charset encoder; possibly a JDK bug
154: fCharsetEncoder = null;
155: fHaveTriedCharsetEncoder = false;
156: }
157: }
158:
159: // As a last resort try to use a sun.io.CharToByteConverter to
160: // determine whether this character is printable. We will always
161: // reach here on JDK 1.3 or below.
162: if (fCharToByteConverter == null) {
163: if (fHaveTriedCToB
164: || !CharToByteConverterMethods.fgConvertersAvailable) {
165: // forget it; nothing we can do...
166: return false;
167: }
168: if (fArgsForMethod == null) {
169: fArgsForMethod = new Object[1];
170: }
171: // try and create the CharToByteConverter
172: try {
173: fArgsForMethod[0] = javaName;
174: fCharToByteConverter = CharToByteConverterMethods.fgGetConverterMethod
175: .invoke(null, fArgsForMethod);
176: } catch (Exception e) {
177: // don't try it again...
178: fHaveTriedCToB = true;
179: return false;
180: }
181: }
182: try {
183: fArgsForMethod[0] = new Character(ch);
184: return ((Boolean) CharToByteConverterMethods.fgCanConvertMethod
185: .invoke(fCharToByteConverter, fArgsForMethod))
186: .booleanValue();
187: } catch (Exception e) {
188: // obviously can't use this converter; probably some kind of
189: // security restriction
190: fCharToByteConverter = null;
191: fHaveTriedCToB = false;
192: return false;
193: }
194: }
195:
196: // is this an encoding name recognized by this JDK?
197: // if not, will throw UnsupportedEncodingException
198: public static void testJavaEncodingName(String name)
199: throws UnsupportedEncodingException {
200: final byte[] bTest = { (byte) 'v', (byte) 'a', (byte) 'l',
201: (byte) 'i', (byte) 'd' };
202: String s = new String(bTest, name);
203: }
204:
205: /**
206: * Holder of methods from java.nio.charset.Charset and java.nio.charset.CharsetEncoder.
207: */
208: static class CharsetMethods {
209:
210: // Method: java.nio.charset.Charset.forName(java.lang.String)
211: private static java.lang.reflect.Method fgCharsetForNameMethod = null;
212:
213: // Method: java.nio.charset.Charset.canEncode()
214: private static java.lang.reflect.Method fgCharsetCanEncodeMethod = null;
215:
216: // Method: java.nio.charset.Charset.newEncoder()
217: private static java.lang.reflect.Method fgCharsetNewEncoderMethod = null;
218:
219: // Method: java.nio.charset.CharsetEncoder.canEncode(char)
220: private static java.lang.reflect.Method fgCharsetEncoderCanEncodeMethod = null;
221:
222: // Flag indicating whether or not java.nio.charset.* is available.
223: private static boolean fgNIOCharsetAvailable = false;
224:
225: private CharsetMethods() {
226: }
227:
228: // Attempt to get methods for Charset and CharsetEncoder on class initialization.
229: static {
230: try {
231: Class charsetClass = Class
232: .forName("java.nio.charset.Charset");
233: Class charsetEncoderClass = Class
234: .forName("java.nio.charset.CharsetEncoder");
235: fgCharsetForNameMethod = charsetClass.getMethod(
236: "forName", new Class[] { String.class });
237: fgCharsetCanEncodeMethod = charsetClass.getMethod(
238: "canEncode", new Class[] {});
239: fgCharsetNewEncoderMethod = charsetClass.getMethod(
240: "newEncoder", new Class[] {});
241: fgCharsetEncoderCanEncodeMethod = charsetEncoderClass
242: .getMethod("canEncode",
243: new Class[] { Character.TYPE });
244: fgNIOCharsetAvailable = true;
245: }
246: // ClassNotFoundException, NoSuchMethodException or SecurityException
247: // Whatever the case, we cannot use java.nio.charset.*.
248: catch (Exception exc) {
249: fgCharsetForNameMethod = null;
250: fgCharsetCanEncodeMethod = null;
251: fgCharsetEncoderCanEncodeMethod = null;
252: fgCharsetNewEncoderMethod = null;
253: fgNIOCharsetAvailable = false;
254: }
255: }
256: }
257:
258: /**
259: * Holder of methods from sun.io.CharToByteConverter.
260: */
261: static class CharToByteConverterMethods {
262:
263: // Method: sun.io.CharToByteConverter.getConverter(java.lang.String)
264: private static java.lang.reflect.Method fgGetConverterMethod = null;
265:
266: // Method: sun.io.CharToByteConverter.canConvert(char)
267: private static java.lang.reflect.Method fgCanConvertMethod = null;
268:
269: // Flag indicating whether or not sun.io.CharToByteConverter is available.
270: private static boolean fgConvertersAvailable = false;
271:
272: private CharToByteConverterMethods() {
273: }
274:
275: // Attempt to get methods for char to byte converter on class initialization.
276: static {
277: try {
278: Class clazz = Class
279: .forName("sun.io.CharToByteConverter");
280: fgGetConverterMethod = clazz.getMethod("getConverter",
281: new Class[] { String.class });
282: fgCanConvertMethod = clazz.getMethod("canConvert",
283: new Class[] { Character.TYPE });
284: fgConvertersAvailable = true;
285: }
286: // ClassNotFoundException, NoSuchMethodException or SecurityException
287: // Whatever the case, we cannot use sun.io.CharToByteConverter.
288: catch (Exception exc) {
289: fgGetConverterMethod = null;
290: fgCanConvertMethod = null;
291: fgConvertersAvailable = false;
292: }
293: }
294: }
295: }
|