19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or more contributor license agreements. See the NOTICE file 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed with this work for additional information 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * regarding copyright ownership. The ASF licenses this file 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to you under the Apache License, Version 2.0 (the "License"); 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * $Id: Encodings.java 471981 2006-11-07 04:28:00Z minchau $ 20212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell */ 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage org.apache.xml.serializer; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStream; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStreamWriter; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.Writer; 2801ed79c5786c527628544828abf8b70d02b989cdChristopher Tateimport java.util.ArrayList; 2901ed79c5786c527628544828abf8b70d02b989cdChristopher Tateimport java.util.Enumeration; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Hashtable; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Properties; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.StringTokenizer; 3461fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez 3561fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez 3661fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez/** 3761fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * Provides information about encodings. Depends on the Java runtime 3861fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * to provides writers for the different encodings. 3961fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <p> 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This class is not a public API. It is only public because it 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is used outside of this package. 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @xsl.usage internal 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic final class Encodings extends Object 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Standard filename for properties file with encodings data. 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 51333b8cba996c8ebb8ca55ebfc5cc536bdd64af94Brad Fitzpatrick private static final String ENCODINGS_FILE = SerializerBase.PKG_PATH+"/Encodings.properties"; 52333b8cba996c8ebb8ca55ebfc5cc536bdd64af94Brad Fitzpatrick 53333b8cba996c8ebb8ca55ebfc5cc536bdd64af94Brad Fitzpatrick /** 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns a writer for the specified encoding based on 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * an output stream. 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is not a public API. 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param output The output stream 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param encoding The encoding MIME name, not a Java name for the encoding. 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A suitable writer 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @throws UnsupportedEncodingException There is no convertor 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to support this encoding 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @xsl.usage internal 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6566fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick static Writer getWriter(OutputStream output, String encoding) 6666fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick throws UnsupportedEncodingException 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < _encodings.length; ++i) 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 7166fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick if (_encodings[i].name.equalsIgnoreCase(encoding)) 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try 749a413f8ffa74bf00333a9ace75b890bdeb7a8c2dChristopher Tate { 759a413f8ffa74bf00333a9ace75b890bdeb7a8c2dChristopher Tate String javaName = _encodings[i].javaName; 769a413f8ffa74bf00333a9ace75b890bdeb7a8c2dChristopher Tate OutputStreamWriter osw = new OutputStreamWriter(output,javaName); 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return osw; 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project catch (java.lang.IllegalArgumentException iae) // java 1.1.8 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // keep trying 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project catch (UnsupportedEncodingException usee) 84212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell { 85c8b055aa8b406a4f10e1962ec0ec7d4131fe9d7dBrian Williammee 86212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell // keep trying 87212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell } 889a413f8ffa74bf00333a9ace75b890bdeb7a8c2dChristopher Tate } 899a413f8ffa74bf00333a9ace75b890bdeb7a8c2dChristopher Tate } 909a413f8ffa74bf00333a9ace75b890bdeb7a8c2dChristopher Tate 91212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell try 92212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell { 93212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell return new OutputStreamWriter(output, encoding); 94212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell } 95212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell catch (java.lang.IllegalArgumentException iae) // java 1.1.8 96212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell { 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new UnsupportedEncodingException(encoding); 9866fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick } 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns the EncodingInfo object for the specified 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * encoding, never null, although the encoding name 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * inside the returned EncodingInfo object will be if 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * we can't find a "real" EncodingInfo for the encoding. 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is not a public API. 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param encoding The encoding 11066fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick * @return The object that is used to determine if 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * characters are in the given encoding. 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @xsl.usage internal 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static EncodingInfo getEncodingInfo(String encoding) 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EncodingInfo ei; 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String normalizedEncoding = toUpperCaseFast(encoding); 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ei = (EncodingInfo) _encodingTableKeyJava.get(normalizedEncoding); 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ei == null) 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ei = (EncodingInfo) _encodingTableKeyMime.get(normalizedEncoding); 12266fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick if (ei == null) { 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We shouldn't have to do this, but just in case. 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ei = new EncodingInfo(null,null, '\u0000'); 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ei; 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Determines if the encoding specified was recognized by the 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * serializer or not. 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 13466fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick * @param encoding The encoding 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return boolean - true if the encoding was recognized else false 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static boolean isRecognizedEncoding(String encoding) 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EncodingInfo ei; 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String normalizedEncoding = encoding.toUpperCase(); 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ei = (EncodingInfo) _encodingTableKeyJava.get(normalizedEncoding); 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ei == null) 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ei = (EncodingInfo) _encodingTableKeyMime.get(normalizedEncoding); 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ei != null) 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A fast and cheap way to uppercase a String that is 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * only made of printable ASCII characters. 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is not a public API. 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param s a String of ASCII characters 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return an uppercased version of the input String, 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * possibly the same String. 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @xsl.usage internal 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static private String toUpperCaseFast(final String s) { 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean different = false; 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int mx = s.length(); 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char[] chars = new char[mx]; 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i=0; i < mx; i++) { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char ch = s.charAt(i); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // is the character a lower case ASCII one? 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ('a' <= ch && ch <= 'z') { 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // a cheap and fast way to uppercase that is good enough 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ch = (char) (ch + ('A' - 'a')); 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project different = true; // the uppercased String is different 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project chars[i] = ch; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // A little optimization, don't call String.valueOf() if 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the uppercased string is the same as the input string. 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String upper; 179edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick if (different) 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project upper = String.valueOf(chars); 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 182edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick upper = s; 183edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick 184edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick return upper; 18566fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick } 186edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The default encoding, ISO style, ISO style. */ 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String DEFAULT_MIME_ENCODING = "UTF-8"; 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 191edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * Get the proper mime encoding. From the XSLT recommendation: "The encoding 192edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * attribute specifies the preferred encoding to use for outputting the result 193edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * tree. XSLT processors are required to respect values of UTF-8 and UTF-16. 194edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * For other values, if the XSLT processor does not support the specified 195edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * encoding it may signal an error; if it does not signal an error it should 196edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * use UTF-8 or UTF-16 instead. The XSLT processor must not use an encoding 197edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * whose name does not match the EncName production of the XML Recommendation 198edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * [XML]. If no encoding attribute is specified, then the XSLT processor should 19966fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick * use either UTF-8 or UTF-16." 200edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * <p> 201edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * This is not a public API. 20266fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick * 203edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * @param encoding Reference to java-style encoding string, which may be null, 204edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * in which case a default will be found. 205edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * 206edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * @return The ISO-style encoding string, or null if failure. 207edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * @xsl.usage internal 20866fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick */ 209edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick static String getMimeEncoding(String encoding) 210edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick { 211edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick 212dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick if (null == encoding) 213dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick { 214dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick try 215dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick { 216dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick 217dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick // Get the default system character encoding. This may be 218dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick // incorrect if they passed in a writer, but right now there 219dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick // seems to be no way to get the encoding from a writer. 220dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick encoding = System.getProperty("file.encoding", "UTF8"); 221dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick 222dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick if (null != encoding) 223dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick { 224dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick 225dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick /* 226dd644c179c1bf47d82d776d7f644e4fc1467159dBrad Fitzpatrick * See if the mime type is equal to UTF8. If you don't 227edf32d01316bd3432c023f17747461b08ae36375Brad Fitzpatrick * do that, then convertJava2MimeEncoding will convert 22866fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick * 8859_1 to "ISO-8859-1", which is not what we want, 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * I think, and I don't think I want to alter the tables 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to convert everything to UTF-8. 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String jencoding = 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (encoding.equalsIgnoreCase("Cp1252") 23401ed79c5786c527628544828abf8b70d02b989cdChristopher Tate || encoding.equalsIgnoreCase("ISO8859_1") 23501ed79c5786c527628544828abf8b70d02b989cdChristopher Tate || encoding.equalsIgnoreCase("8859_1") 23601ed79c5786c527628544828abf8b70d02b989cdChristopher Tate || encoding.equalsIgnoreCase("UTF8")) 23701ed79c5786c527628544828abf8b70d02b989cdChristopher Tate ? DEFAULT_MIME_ENCODING 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : convertJava2MimeEncoding(encoding); 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encoding = 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (null != jencoding) ? jencoding : DEFAULT_MIME_ENCODING; 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encoding = DEFAULT_MIME_ENCODING; 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project catch (SecurityException se) 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encoding = DEFAULT_MIME_ENCODING; 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encoding = convertJava2MimeEncoding(encoding); 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return encoding; 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 260212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell 261212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell /** 26201ed79c5786c527628544828abf8b70d02b989cdChristopher Tate * Try the best we can to convert a Java encoding to a XML-style encoding. 26301ed79c5786c527628544828abf8b70d02b989cdChristopher Tate * <p> 26401ed79c5786c527628544828abf8b70d02b989cdChristopher Tate * This is not a public API. 26501ed79c5786c527628544828abf8b70d02b989cdChristopher Tate * @param encoding non-null reference to encoding string, java style. 266212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell * 267212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell * @return ISO-style encoding string. 268212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell * @xsl.usage internal 269212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell */ 270212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell private static String convertJava2MimeEncoding(String encoding) 271212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell { 272212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell EncodingInfo enc = 273212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell (EncodingInfo) _encodingTableKeyJava.get(toUpperCaseFast(encoding)); 274212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell if (null != enc) 275212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell return enc.name; 276212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell return encoding; 277212db7d3f8ce5297f4a556234a9c0675c697f1cfAdam Powell } 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Try the best we can to convert a Java encoding to a XML-style encoding. 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This is not a public API. 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param encoding non-null reference to encoding string, java style. 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return ISO-style encoding string. 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method is not a public API. 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @xsl.usage internal 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static String convertMime2JavaEncoding(String encoding) 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < _encodings.length; ++i) 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (_encodings[i].name.equalsIgnoreCase(encoding)) 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return _encodings[i].javaName; 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return encoding; 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Load a list of all the supported encodings. 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * System property "encodings" formatted using URL syntax may define an 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * external encodings list. Thanks to Sergey Ushakov for the code 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * contribution! 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @xsl.usage internal 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static EncodingInfo[] loadEncodingInfo() 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final InputStream is; 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SecuritySupport ss = SecuritySupport.getInstance(); 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project is = ss.getResourceAsStream(ObjectFactory.findClassLoader(), 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ENCODINGS_FILE); 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Properties props = new Properties(); 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (is != null) { 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project props.load(is); 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project is.close(); 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Seems to be no real need to force failure here, let the 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // system do its best... The issue is not really very critical, 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // and the output will be in any case _correct_ though maybe not 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // always human-friendly... :) 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // But maybe report/log the resource problem? 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Any standard ways to report/log errors (in static context)? 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int totalEntries = props.size(); 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List encodingInfo_list = new ArrayList(); 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Enumeration keys = props.keys(); 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < totalEntries; ++i) 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String javaName = (String) keys.nextElement(); 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String val = props.getProperty(javaName); 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int len = lengthOfMimeNames(val); 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String mimeName; 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char highChar; 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (len == 0) 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // There is no property value, only the javaName, so try and recover 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mimeName = javaName; 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project highChar = '\u0000'; // don't know the high code point, will need to test every character 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Get the substring after the Mime names 358de0c99e89bfe2df43e363f2521c55d5da166ddadAndrew Solovay final String highVal = val.substring(len).trim(); 359de0c99e89bfe2df43e363f2521c55d5da166ddadAndrew Solovay highChar = (char) Integer.decode(highVal).intValue(); 360de0c99e89bfe2df43e363f2521c55d5da166ddadAndrew Solovay } 361de0c99e89bfe2df43e363f2521c55d5da166ddadAndrew Solovay catch( NumberFormatException e) { 362de0c99e89bfe2df43e363f2521c55d5da166ddadAndrew Solovay highChar = 0; 363de0c99e89bfe2df43e363f2521c55d5da166ddadAndrew Solovay } 364de0c99e89bfe2df43e363f2521c55d5da166ddadAndrew Solovay String mimeNames = val.substring(0, len); 365de0c99e89bfe2df43e363f2521c55d5da166ddadAndrew Solovay StringTokenizer st = 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new StringTokenizer(mimeNames, ","); 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (boolean first = true; 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project st.hasMoreTokens(); 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project first = false) 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mimeName = st.nextToken(); 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project EncodingInfo ei = new EncodingInfo(mimeName, javaName, highChar); 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project encodingInfo_list.add(ei); 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project _encodingTableKeyMime.put(mimeName.toUpperCase(), ei); 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (first) 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project _encodingTableKeyJava.put(javaName.toUpperCase(), ei); 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 379 } 380 // Convert the Vector of EncodingInfo objects into an array of them, 381 // as that is the kind of thing this method returns. 382 EncodingInfo[] ret_ei = new EncodingInfo[encodingInfo_list.size()]; 383 encodingInfo_list.toArray(ret_ei); 384 return ret_ei; 385 } 386 catch (java.net.MalformedURLException mue) 387 { 388 throw new org.apache.xml.serializer.utils.WrappedRuntimeException(mue); 389 } 390 catch (java.io.IOException ioe) 391 { 392 throw new org.apache.xml.serializer.utils.WrappedRuntimeException(ioe); 393 } 394 } 395 396 /** 397 * Get the length of the Mime names within the property value 398 * @param val The value of the property, which should contain a comma 399 * separated list of Mime names, followed optionally by a space and the 400 * high char value 401 * @return 402 */ 403 private static int lengthOfMimeNames(String val) { 404 // look for the space preceding the optional high char 405 int len = val.indexOf(' '); 406 // If len is zero it means the optional part is not there, so 407 // the value must be all Mime names, so set the length appropriately 408 if (len < 0) 409 len = val.length(); 410 411 return len; 412 } 413 414 /** 415 * Return true if the character is the high member of a surrogate pair. 416 * <p> 417 * This is not a public API. 418 * @param ch the character to test 419 * @xsl.usage internal 420 */ 421 static boolean isHighUTF16Surrogate(char ch) { 422 return ('\uD800' <= ch && ch <= '\uDBFF'); 423 } 424 /** 425 * Return true if the character is the low member of a surrogate pair. 426 * <p> 427 * This is not a public API. 428 * @param ch the character to test 429 * @xsl.usage internal 430 */ 431 static boolean isLowUTF16Surrogate(char ch) { 432 return ('\uDC00' <= ch && ch <= '\uDFFF'); 433 } 434 /** 435 * Return the unicode code point represented by the high/low surrogate pair. 436 * <p> 437 * This is not a public API. 438 * @param highSurrogate the high char of the high/low pair 439 * @param lowSurrogate the low char of the high/low pair 440 * @xsl.usage internal 441 */ 442 static int toCodePoint(char highSurrogate, char lowSurrogate) { 443 int codePoint = 444 ((highSurrogate - 0xd800) << 10) 445 + (lowSurrogate - 0xdc00) 446 + 0x10000; 447 return codePoint; 448 } 449 /** 450 * Return the unicode code point represented by the char. 451 * A bit of a dummy method, since all it does is return the char, 452 * but as an int value. 453 * <p> 454 * This is not a public API. 455 * @param ch the char. 456 * @xsl.usage internal 457 */ 458 static int toCodePoint(char ch) { 459 int codePoint = ch; 460 return codePoint; 461 } 462 463 /** 464 * Characters with values at or below the high code point are 465 * in the encoding. Code point values above this one may or may 466 * not be in the encoding, but lower ones certainly are. 467 * <p> 468 * This is for performance. 469 * 470 * @param encoding The encoding 471 * @return The code point for which characters at or below this code point 472 * are in the encoding. Characters with higher code point may or may not be 473 * in the encoding. A value of zero is returned if the high code point is unknown. 474 * <p> 475 * This method is not a public API. 476 * @xsl.usage internal 477 */ 478 static public char getHighChar(String encoding) 479 { 480 final char highCodePoint; 481 EncodingInfo ei; 482 483 String normalizedEncoding = toUpperCaseFast(encoding); 484 ei = (EncodingInfo) _encodingTableKeyJava.get(normalizedEncoding); 485 if (ei == null) 486 ei = (EncodingInfo) _encodingTableKeyMime.get(normalizedEncoding); 487 if (ei != null) 488 highCodePoint = ei.getHighChar(); 489 else 490 highCodePoint = 0; 491 return highCodePoint; 492 } 493 494 private static final Hashtable _encodingTableKeyJava = new Hashtable(); 495 private static final Hashtable _encodingTableKeyMime = new Hashtable(); 496 private static final EncodingInfo[] _encodings = loadEncodingInfo(); 497} 498