KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > serializer > Encodings


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: Encodings.java,v 1.8 2004/02/23 10:29:37 aruny Exp $
18  */

19 package org.apache.xml.serializer;
20
21 import java.io.InputStream JavaDoc;
22 import java.io.OutputStream JavaDoc;
23 import java.io.OutputStreamWriter JavaDoc;
24 import java.io.UnsupportedEncodingException JavaDoc;
25 import java.io.Writer JavaDoc;
26 import java.lang.reflect.Method JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.util.Enumeration JavaDoc;
29 import java.util.Hashtable JavaDoc;
30 import java.util.Properties JavaDoc;
31 import java.util.StringTokenizer JavaDoc;
32 import java.security.PrivilegedAction JavaDoc;
33 import java.security.AccessController JavaDoc;
34
35
36 /**
37  * Provides information about encodings. Depends on the Java runtime
38  * to provides writers for the different encodings, but can be used
39  * to override encoding names and provide the last printable character
40  * for each encoding.
41  *
42  * @version $Revision: 1.8 $ $Date: 2004/02/23 10:29:37 $
43  * @author <a HREF="mailto:arkin@intalio.com">Assaf Arkin</a>
44  */

45
46 public class Encodings extends Object JavaDoc
47 {
48
49     /**
50      * The last printable character for unknown encodings.
51      */

52     static final int m_defaultLastPrintable = 0x7F;
53
54     /**
55      * Standard filename for properties file with encodings data.
56      */

57     static final String JavaDoc ENCODINGS_FILE = "org/apache/xml/serializer/Encodings.properties";
58
59     /**
60      * Standard filename for properties file with encodings data.
61      */

62     static final String JavaDoc ENCODINGS_PROP = "org.apache.xalan.serialize.encodings";
63
64     /** SUN JVM internal ByteToChar converter method */
65     private static final Method
66         SUN_CHAR2BYTE_CONVERTER_METHOD = findCharToByteConverterMethod();
67
68     private static Method findCharToByteConverterMethod() {
69         try
70         {
71             AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
72                 public Object JavaDoc run() {
73                     try {
74                         Class JavaDoc charToByteConverterClass = (Class JavaDoc)
75                             Class.forName("sun.io.CharToByteConverter");
76                         Class JavaDoc argTypes[] = {String JavaDoc.class};
77                         return charToByteConverterClass.getMethod("getConverter", argTypes);
78                     }
79                     catch (Exception JavaDoc e) {
80                         throw new RuntimeException JavaDoc(e.toString());
81                     }
82                 }});
83         }
84         catch (Exception JavaDoc e)
85         {
86             System.err.println(
87                 "Warning: Could not get charToByteConverterClass!");
88         }
89
90         return null;
91     }
92
93     /**
94      * Returns a writer for the specified encoding based on
95      * an output stream.
96      *
97      * @param output The output stream
98      * @param encoding The encoding
99      * @return A suitable writer
100      * @throws UnsupportedEncodingException There is no convertor
101      * to support this encoding
102      */

103     public static Writer JavaDoc getWriter(OutputStream JavaDoc output, String JavaDoc encoding)
104         throws UnsupportedEncodingException JavaDoc
105     {
106
107         for (int i = 0; i < _encodings.length; ++i)
108         {
109             if (_encodings[i].name.equalsIgnoreCase(encoding))
110             {
111                 try
112                 {
113                     return new OutputStreamWriter JavaDoc(
114                         output,
115                         _encodings[i].javaName);
116                 }
117                 catch (java.lang.IllegalArgumentException JavaDoc iae) // java 1.1.8
118
{
119                     // keep trying
120
}
121                 catch (UnsupportedEncodingException JavaDoc usee)
122                 {
123
124                     // keep trying
125
}
126             }
127         }
128
129         try
130         {
131             return new OutputStreamWriter JavaDoc(output, encoding);
132         }
133         catch (java.lang.IllegalArgumentException JavaDoc iae) // java 1.1.8
134
{
135             throw new UnsupportedEncodingException JavaDoc(encoding);
136         }
137     }
138
139     /**
140      * Returns an opaque CharToByte converter for the specified encoding.
141      *
142      * @param encoding The encoding
143      * @return An object which should be a sun.io.CharToByteConverter, or null.
144      */

145     public static Object JavaDoc getCharToByteConverter(String JavaDoc encoding)
146     {
147         if (SUN_CHAR2BYTE_CONVERTER_METHOD == null) {
148             return null;
149         }
150
151         Object JavaDoc args[] = new Object JavaDoc[1];
152         for (int i = 0; i < _encodings.length; ++i)
153         {
154             if (_encodings[i].name.equalsIgnoreCase(encoding))
155             {
156                 try
157                 {
158                     args[0] = _encodings[i].javaName;
159                     Object JavaDoc converter =
160                         SUN_CHAR2BYTE_CONVERTER_METHOD.invoke(null, args);
161                     if (null != converter)
162                         return converter;
163                 }
164                 catch (Exception JavaDoc iae)
165                 {
166                     // keep trying
167
}
168             }
169         }
170
171         return null;
172     }
173
174     /**
175      * Returns the last printable character for the specified
176      * encoding.
177      *
178      * @param encoding The encoding
179      * @return The last printable character
180      */

181     public static int getLastPrintable(String JavaDoc encoding)
182     {
183         EncodingInfo ei;
184
185         String JavaDoc normalizedEncoding = encoding.toUpperCase();
186         ei = (EncodingInfo) _encodingTableKeyJava.get(normalizedEncoding);
187         if (ei == null)
188             ei = (EncodingInfo) _encodingTableKeyMime.get(normalizedEncoding);
189         if (ei != null)
190             return ei.lastPrintable;
191         return m_defaultLastPrintable;
192     }
193
194     /**
195      * Returns the last printable character for an unspecified
196      * encoding.
197      *
198      * @return the default size
199      */

200     public static int getLastPrintable()
201     {
202         return m_defaultLastPrintable;
203     }
204
205     /** The default encoding, ISO style, ISO style. */
206     public static final String JavaDoc DEFAULT_MIME_ENCODING = "UTF-8";
207
208     /**
209      * Get the proper mime encoding. From the XSLT recommendation: "The encoding
210      * attribute specifies the preferred encoding to use for outputting the result
211      * tree. XSLT processors are required to respect values of UTF-8 and UTF-16.
212      * For other values, if the XSLT processor does not support the specified
213      * encoding it may signal an error; if it does not signal an error it should
214      * use UTF-8 or UTF-16 instead. The XSLT processor must not use an encoding
215      * whose name does not match the EncName production of the XML Recommendation
216      * [XML]. If no encoding attribute is specified, then the XSLT processor should
217      * use either UTF-8 or UTF-16."
218      *
219      * @param encoding Reference to java-style encoding string, which may be null,
220      * in which case a default will be found.
221      *
222      * @return The ISO-style encoding string, or null if failure.
223      */

224     public static String JavaDoc getMimeEncoding(String JavaDoc encoding)
225     {
226
227         if (null == encoding)
228         {
229             try
230             {
231
232                 // Get the default system character encoding. This may be
233
// incorrect if they passed in a writer, but right now there
234
// seems to be no way to get the encoding from a writer.
235
encoding = System.getProperty("file.encoding", "UTF8");
236
237                 if (null != encoding)
238                 {
239
240                     /*
241                     * See if the mime type is equal to UTF8. If you don't
242                     * do that, then convertJava2MimeEncoding will convert
243                     * 8859_1 to "ISO-8859-1", which is not what we want,
244                     * I think, and I don't think I want to alter the tables
245                     * to convert everything to UTF-8.
246                     */

247                     String JavaDoc jencoding =
248                         (encoding.equalsIgnoreCase("Cp1252")
249                             || encoding.equalsIgnoreCase("ISO8859_1")
250                             || encoding.equalsIgnoreCase("8859_1")
251                             || encoding.equalsIgnoreCase("UTF8"))
252                             ? DEFAULT_MIME_ENCODING
253                             : convertJava2MimeEncoding(encoding);
254
255                     encoding =
256                         (null != jencoding) ? jencoding : DEFAULT_MIME_ENCODING;
257                 }
258                 else
259                 {
260                     encoding = DEFAULT_MIME_ENCODING;
261                 }
262             }
263             catch (SecurityException JavaDoc se)
264             {
265                 encoding = DEFAULT_MIME_ENCODING;
266             }
267         }
268         else
269         {
270             encoding = convertJava2MimeEncoding(encoding);
271         }
272
273         return encoding;
274     }
275
276     /**
277      * Try the best we can to convert a Java encoding to a XML-style encoding.
278      *
279      * @param encoding non-null reference to encoding string, java style.
280      *
281      * @return ISO-style encoding string.
282      */

283     public static String JavaDoc convertJava2MimeEncoding(String JavaDoc encoding)
284     {
285         EncodingInfo enc =
286             (EncodingInfo) _encodingTableKeyJava.get(encoding.toUpperCase());
287         if (null != enc)
288             return enc.name;
289         return encoding;
290     }
291
292     /**
293      * Try the best we can to convert a Java encoding to a XML-style encoding.
294      *
295      * @param encoding non-null reference to encoding string, java style.
296      *
297      * @return ISO-style encoding string.
298      */

299     public static String JavaDoc convertMime2JavaEncoding(String JavaDoc encoding)
300     {
301
302         for (int i = 0; i < _encodings.length; ++i)
303         {
304             if (_encodings[i].name.equalsIgnoreCase(encoding))
305             {
306                 return _encodings[i].javaName;
307             }
308         }
309
310         return encoding;
311     }
312
313     /**
314      * Load a list of all the supported encodings.
315      *
316      * System property "encodings" formatted using URL syntax may define an
317      * external encodings list. Thanks to Sergey Ushakov for the code
318      * contribution!
319      */

320     private static EncodingInfo[] loadEncodingInfo()
321     {
322         URL JavaDoc url = null;
323         try
324         {
325             String JavaDoc urlString = null;
326             InputStream JavaDoc is = null;
327
328             try
329             {
330                 urlString = System.getProperty(ENCODINGS_PROP, "");
331             }
332             catch (SecurityException JavaDoc e)
333             {
334             }
335
336             if (urlString != null && urlString.length() > 0) {
337                 url = new URL JavaDoc(urlString);
338                 is = url.openStream();
339             }
340
341             if (is == null) {
342                 SecuritySupport ss = SecuritySupport.getInstance();
343                 is = ss.getResourceAsStream(ObjectFactory.findClassLoader(),
344                                             ENCODINGS_FILE);
345             }
346
347             Properties JavaDoc props = new Properties JavaDoc();
348             if (is != null) {
349                 props.load(is);
350                 is.close();
351             } else {
352                 // Seems to be no real need to force failure here, let the
353
// system do its best... The issue is not really very critical,
354
// and the output will be in any case _correct_ though maybe not
355
// always human-friendly... :)
356
// But maybe report/log the resource problem?
357
// Any standard ways to report/log errors (in static context)?
358
}
359
360             int totalEntries = props.size();
361             int totalMimeNames = 0;
362             Enumeration JavaDoc keys = props.keys();
363             for (int i = 0; i < totalEntries; ++i)
364             {
365                 String JavaDoc javaName = (String JavaDoc) keys.nextElement();
366                 String JavaDoc val = props.getProperty(javaName);
367                 totalMimeNames++;
368                 int pos = val.indexOf(' ');
369                 for (int j = 0; j < pos; ++j)
370                     if (val.charAt(j) == ',')
371                         totalMimeNames++;
372             }
373             EncodingInfo[] ret = new EncodingInfo[totalMimeNames];
374             int j = 0;
375             keys = props.keys();
376             for (int i = 0; i < totalEntries; ++i)
377             {
378                 String JavaDoc javaName = (String JavaDoc) keys.nextElement();
379                 String JavaDoc val = props.getProperty(javaName);
380                 int pos = val.indexOf(' ');
381                 String JavaDoc mimeName;
382                 int lastPrintable;
383                 if (pos < 0)
384                 {
385                     // Maybe report/log this problem?
386
// "Last printable character not defined for encoding " +
387
// mimeName + " (" + val + ")" ...
388
mimeName = val;
389                     lastPrintable = 0x00FF;
390                 }
391                 else
392                 {
393                     lastPrintable =
394                         Integer.decode(val.substring(pos).trim()).intValue();
395                     StringTokenizer JavaDoc st =
396                         new StringTokenizer JavaDoc(val.substring(0, pos), ",");
397                     for (boolean first = true;
398                         st.hasMoreTokens();
399                         first = false)
400                     {
401                         mimeName = st.nextToken();
402                         ret[j] =
403                             new EncodingInfo(mimeName, javaName, lastPrintable);
404                         _encodingTableKeyMime.put(
405                             mimeName.toUpperCase(),
406                             ret[j]);
407                         if (first)
408                             _encodingTableKeyJava.put(
409                                 javaName.toUpperCase(),
410                                 ret[j]);
411                         j++;
412                     }
413                 }
414             }
415             return ret;
416         }
417         catch (java.net.MalformedURLException JavaDoc mue)
418         {
419             throw new org.apache.xml.utils.WrappedRuntimeException(mue);
420         }
421         catch (java.io.IOException JavaDoc ioe)
422         {
423             throw new org.apache.xml.utils.WrappedRuntimeException(ioe);
424         }
425     }
426
427     private static final Hashtable JavaDoc _encodingTableKeyJava = new Hashtable JavaDoc();
428     private static final Hashtable JavaDoc _encodingTableKeyMime = new Hashtable JavaDoc();
429     private static final EncodingInfo[] _encodings = loadEncodingInfo();
430 }
431
Popular Tags