src/share/classes/java/lang/StringCoding.java

Print this page


   1 /*
   2  * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package java.lang;
  27 
  28 import java.io.CharConversionException;
  29 import java.io.UnsupportedEncodingException;
  30 import java.lang.ref.SoftReference;
  31 import java.nio.ByteBuffer;
  32 import java.nio.CharBuffer;
  33 import java.nio.BufferOverflowException;
  34 import java.nio.BufferUnderflowException;
  35 import java.nio.charset.Charset;
  36 import java.nio.charset.CharsetDecoder;
  37 import java.nio.charset.CharsetEncoder;
  38 import java.nio.charset.CharacterCodingException;
  39 import java.nio.charset.CoderResult;
  40 import java.nio.charset.CodingErrorAction;
  41 import java.nio.charset.IllegalCharsetNameException;
  42 import java.nio.charset.MalformedInputException;
  43 import java.nio.charset.UnsupportedCharsetException;
  44 import java.util.Arrays;
  45 import sun.misc.MessageUtils;
  46 import sun.nio.cs.HistoricallyNamedCharset;


  47 
  48 /**
  49  * Utility class for string encoding and decoding.
  50  */
  51 
  52 class StringCoding {
  53 
  54     private StringCoding() { }
  55 
  56     /** The cached coders for each thread */
  57     private final static ThreadLocal<SoftReference<StringDecoder>> decoder =
  58         new ThreadLocal<SoftReference<StringDecoder>>();
  59     private final static ThreadLocal<SoftReference<StringEncoder>> encoder =
  60         new ThreadLocal<SoftReference<StringEncoder>>();
  61 
  62     private static boolean warnUnsupportedCharset = true;
  63 
  64     private static <T> T deref(ThreadLocal<SoftReference<T>> tl) {
  65         SoftReference<T> sr = tl.get();
  66         if (sr == null)
  67             return null;
  68         return sr.get();
  69     }
  70 
  71     private static <T> void set(ThreadLocal<SoftReference<T>> tl, T ob) {
  72         tl.set(new SoftReference<T>(ob));
  73     }
  74 
  75     // Trim the given byte array to the given length
  76     //
  77     private static byte[] safeTrim(byte[] ba, int len, Charset cs) {
  78         if (len == ba.length
  79             && (System.getSecurityManager() == null
  80                 || cs.getClass().getClassLoader0() == null))
  81             return ba;
  82         else
  83             return Arrays.copyOf(ba, len);
  84     }
  85 
  86     // Trim the given char array to the given length
  87     //
  88     private static char[] safeTrim(char[] ca, int len, Charset cs) {
  89         if (len == ca.length
  90             && (System.getSecurityManager() == null
  91                 || cs.getClass().getClassLoader0() == null))
  92             return ca;
  93         else
  94             return Arrays.copyOf(ca, len);
  95     }
  96 
  97     private static int scale(int len, float expansionFactor) {
  98         // We need to perform double, not float, arithmetic; otherwise
  99         // we lose low order bits when len is larger than 2**24.
 100         return (int)(len * (double)expansionFactor);
 101     }
 102 
 103     private static Charset lookupCharset(String csn) {
 104         if (Charset.isSupported(csn)) {
 105             try {
 106                 return Charset.forName(csn);
 107             } catch (UnsupportedCharsetException x) {
 108                 throw new Error(x);
 109             }
 110         }
 111         return null;
 112     }
 113 
 114     private static void warnUnsupportedCharset(String csn) {
 115         if (warnUnsupportedCharset) {
 116             // Use sun.misc.MessageUtils rather than the Logging API or
 117             // System.err since this method may be called during VM
 118             // initialization before either is available.
 119             MessageUtils.err("WARNING: Default charset " + csn +
 120                              " not supported, using ISO-8859-1 instead");
 121             warnUnsupportedCharset = false;
 122         }
 123     }
 124 
 125 
 126     // -- Decoding --
 127     private static class StringDecoder {
 128         private final String requestedCharsetName;
 129         private final Charset cs;
 130         private final CharsetDecoder cd;

 131 
 132         private StringDecoder(Charset cs, String rcn) {
 133             this.requestedCharsetName = rcn;
 134             this.cs = cs;
 135             this.cd = cs.newDecoder()
 136                 .onMalformedInput(CodingErrorAction.REPLACE)
 137                 .onUnmappableCharacter(CodingErrorAction.REPLACE);

 138         }
 139 
 140         String charsetName() {
 141             if (cs instanceof HistoricallyNamedCharset)
 142                 return ((HistoricallyNamedCharset)cs).historicalName();
 143             return cs.name();
 144         }
 145 
 146         final String requestedCharsetName() {
 147             return requestedCharsetName;
 148         }
 149 
 150         char[] decode(byte[] ba, int off, int len) {
 151             int en = scale(len, cd.maxCharsPerByte());
 152             char[] ca = new char[en];
 153             if (len == 0)
 154                 return ca;




 155             cd.reset();
 156             ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
 157             CharBuffer cb = CharBuffer.wrap(ca);
 158             try {
 159                 CoderResult cr = cd.decode(bb, cb, true);
 160                 if (!cr.isUnderflow())
 161                     cr.throwException();
 162                 cr = cd.flush(cb);
 163                 if (!cr.isUnderflow())
 164                     cr.throwException();
 165             } catch (CharacterCodingException x) {
 166                 // Substitution is always enabled,
 167                 // so this shouldn't happen
 168                 throw new Error(x);
 169             }
 170             return safeTrim(ca, cb.position(), cs);
 171         }
 172 
 173     }

 174 
 175     static char[] decode(String charsetName, byte[] ba, int off, int len)
 176         throws UnsupportedEncodingException
 177     {
 178         StringDecoder sd = deref(decoder);
 179         String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
 180         if ((sd == null) || !(csn.equals(sd.requestedCharsetName())
 181                               || csn.equals(sd.charsetName()))) {
 182             sd = null;
 183             try {
 184                 Charset cs = lookupCharset(csn);
 185                 if (cs != null)
 186                     sd = new StringDecoder(cs, csn);
 187             } catch (IllegalCharsetNameException x) {}
 188             if (sd == null)
 189                 throw new UnsupportedEncodingException(csn);
 190             set(decoder, sd);
 191         }
 192         return sd.decode(ba, off, len);
 193     }
 194 
 195     static char[] decode(Charset cs, byte[] ba, int off, int len) {
 196         StringDecoder sd = new StringDecoder(cs, cs.name());
 197         return sd.decode(Arrays.copyOfRange(ba, off, off + len), 0, len);
























 198     }

























 199 
 200     static char[] decode(byte[] ba, int off, int len) {
 201         String csn = Charset.defaultCharset().name();
 202         try {
 203             return decode(csn, ba, off, len);
 204         } catch (UnsupportedEncodingException x) {
 205             warnUnsupportedCharset(csn);
 206         }
 207         try {
 208             return decode("ISO-8859-1", ba, off, len);
 209         } catch (UnsupportedEncodingException x) {
 210             // If this code is hit during VM initialization, MessageUtils is
 211             // the only way we will be able to get any kind of error message.
 212             MessageUtils.err("ISO-8859-1 charset not available: "
 213                              + x.toString());
 214             // If we can not find ISO-8859-1 (a required encoding) then things
 215             // are seriously wrong with the installation.
 216             System.exit(1);
 217             return null;
 218         }
 219     }
 220 
 221 
 222 
 223 
 224     // -- Encoding --
 225     private static class StringEncoder {
 226         private Charset cs;
 227         private CharsetEncoder ce;
 228         private final String requestedCharsetName;

 229 
 230         private StringEncoder(Charset cs, String rcn) {
 231             this.requestedCharsetName = rcn;
 232             this.cs = cs;
 233             this.ce = cs.newEncoder()
 234                 .onMalformedInput(CodingErrorAction.REPLACE)
 235                 .onUnmappableCharacter(CodingErrorAction.REPLACE);

 236         }
 237 
 238         String charsetName() {
 239             if (cs instanceof HistoricallyNamedCharset)
 240                 return ((HistoricallyNamedCharset)cs).historicalName();
 241             return cs.name();
 242         }
 243 
 244         final String requestedCharsetName() {
 245             return requestedCharsetName;
 246         }
 247 
 248         byte[] encode(char[] ca, int off, int len) {
 249             int en = scale(len, ce.maxBytesPerChar());
 250             byte[] ba = new byte[en];
 251             if (len == 0)
 252                 return ba;
 253 



 254             ce.reset();
 255             ByteBuffer bb = ByteBuffer.wrap(ba);
 256             CharBuffer cb = CharBuffer.wrap(ca, off, len);
 257             try {
 258                 CoderResult cr = ce.encode(cb, bb, true);
 259                 if (!cr.isUnderflow())
 260                     cr.throwException();
 261                 cr = ce.flush(bb);
 262                 if (!cr.isUnderflow())
 263                     cr.throwException();
 264             } catch (CharacterCodingException x) {
 265                 // Substitution is always enabled,
 266                 // so this shouldn't happen
 267                 throw new Error(x);
 268             }
 269             return safeTrim(ba, bb.position(), cs);
 270         }
 271     }

 272 
 273     static byte[] encode(String charsetName, char[] ca, int off, int len)
 274         throws UnsupportedEncodingException
 275     {
 276         StringEncoder se = deref(encoder);
 277         String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
 278         if ((se == null) || !(csn.equals(se.requestedCharsetName())
 279                               || csn.equals(se.charsetName()))) {
 280             se = null;
 281             try {
 282                 Charset cs = lookupCharset(csn);
 283                 if (cs != null)
 284                     se = new StringEncoder(cs, csn);
 285             } catch (IllegalCharsetNameException x) {}
 286             if (se == null)
 287                 throw new UnsupportedEncodingException (csn);
 288             set(encoder, se);
 289         }
 290         return se.encode(ca, off, len);
 291     }
 292 
 293     static byte[] encode(Charset cs, char[] ca, int off, int len) {
 294         StringEncoder se = new StringEncoder(cs, cs.name());
 295         return se.encode(Arrays.copyOfRange(ca, off, off + len), 0, len);








 296     }























 297 
 298     static byte[] encode(char[] ca, int off, int len) {
 299         String csn = Charset.defaultCharset().name();
 300         try {
 301             return encode(csn, ca, off, len);
 302         } catch (UnsupportedEncodingException x) {
 303             warnUnsupportedCharset(csn);
 304         }
 305         try {
 306             return encode("ISO-8859-1", ca, off, len);
 307         } catch (UnsupportedEncodingException x) {
 308             // If this code is hit during VM initialization, MessageUtils is
 309             // the only way we will be able to get any kind of error message.
 310             MessageUtils.err("ISO-8859-1 charset not available: "
 311                              + x.toString());
 312             // If we can not find ISO-8859-1 (a required encoding) then things
 313             // are seriously wrong with the installation.
 314             System.exit(1);
 315             return null;
 316         }
   1 /*
   2  * Copyright 2000-2009 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package java.lang;
  27 

  28 import java.io.UnsupportedEncodingException;
  29 import java.lang.ref.SoftReference;
  30 import java.nio.ByteBuffer;
  31 import java.nio.CharBuffer;


  32 import java.nio.charset.Charset;
  33 import java.nio.charset.CharsetDecoder;
  34 import java.nio.charset.CharsetEncoder;
  35 import java.nio.charset.CharacterCodingException;
  36 import java.nio.charset.CoderResult;
  37 import java.nio.charset.CodingErrorAction;
  38 import java.nio.charset.IllegalCharsetNameException;

  39 import java.nio.charset.UnsupportedCharsetException;
  40 import java.util.Arrays;
  41 import sun.misc.MessageUtils;
  42 import sun.nio.cs.HistoricallyNamedCharset;
  43 import sun.nio.cs.ArrayDecoder;
  44 import sun.nio.cs.ArrayEncoder;
  45 
  46 /**
  47  * Utility class for string encoding and decoding.
  48  */
  49 
  50 class StringCoding {
  51 
  52     private StringCoding() { }
  53 
  54     /** The cached coders for each thread */
  55     private final static ThreadLocal<SoftReference<StringDecoder>> decoder =
  56         new ThreadLocal<SoftReference<StringDecoder>>();
  57     private final static ThreadLocal<SoftReference<StringEncoder>> encoder =
  58         new ThreadLocal<SoftReference<StringEncoder>>();
  59 
  60     private static boolean warnUnsupportedCharset = true;
  61 
  62     private static <T> T deref(ThreadLocal<SoftReference<T>> tl) {
  63         SoftReference<T> sr = tl.get();
  64         if (sr == null)
  65             return null;
  66         return sr.get();
  67     }
  68 
  69     private static <T> void set(ThreadLocal<SoftReference<T>> tl, T ob) {
  70         tl.set(new SoftReference<T>(ob));
  71     }
  72 
  73     // Trim the given byte array to the given length
  74     //
  75     private static byte[] safeTrim(byte[] ba, int len, Charset cs, boolean isTrusted) {
  76         if (len == ba.length && (isTrusted || System.getSecurityManager() == null))


  77             return ba;
  78         else
  79             return Arrays.copyOf(ba, len);
  80     }
  81 
  82     // Trim the given char array to the given length
  83     //
  84     private static char[] safeTrim(char[] ca, int len,
  85                                    Charset cs, boolean isTrusted) {
  86         if (len == ca.length && (isTrusted || System.getSecurityManager() == null))

  87             return ca;
  88         else
  89             return Arrays.copyOf(ca, len);
  90     }
  91 
  92     private static int scale(int len, float expansionFactor) {
  93         // We need to perform double, not float, arithmetic; otherwise
  94         // we lose low order bits when len is larger than 2**24.
  95         return (int)(len * (double)expansionFactor);
  96     }
  97 
  98     private static Charset lookupCharset(String csn) {
  99         if (Charset.isSupported(csn)) {
 100             try {
 101                 return Charset.forName(csn);
 102             } catch (UnsupportedCharsetException x) {
 103                 throw new Error(x);
 104             }
 105         }
 106         return null;
 107     }
 108 
 109     private static void warnUnsupportedCharset(String csn) {
 110         if (warnUnsupportedCharset) {
 111             // Use sun.misc.MessageUtils rather than the Logging API or
 112             // System.err since this method may be called during VM
 113             // initialization before either is available.
 114             MessageUtils.err("WARNING: Default charset " + csn +
 115                              " not supported, using ISO-8859-1 instead");
 116             warnUnsupportedCharset = false;
 117         }
 118     }
 119 
 120 
 121     // -- Decoding --
 122     private static class StringDecoder {
 123         private final String requestedCharsetName;
 124         private final Charset cs;
 125         private final CharsetDecoder cd;
 126         private final boolean isTrusted;
 127 
 128         private StringDecoder(Charset cs, String rcn) {
 129             this.requestedCharsetName = rcn;
 130             this.cs = cs;
 131             this.cd = cs.newDecoder()
 132                 .onMalformedInput(CodingErrorAction.REPLACE)
 133                 .onUnmappableCharacter(CodingErrorAction.REPLACE);
 134             this.isTrusted = (cs.getClass().getClassLoader0() == null); 
 135         }
 136 
 137         String charsetName() {
 138             if (cs instanceof HistoricallyNamedCharset)
 139                 return ((HistoricallyNamedCharset)cs).historicalName();
 140             return cs.name();
 141         }
 142 
 143         final String requestedCharsetName() {
 144             return requestedCharsetName;
 145         }
 146 
 147         char[] decode(byte[] ba, int off, int len) {
 148             int en = scale(len, cd.maxCharsPerByte());
 149             char[] ca = new char[en];
 150             if (len == 0)
 151                 return ca;
 152             if (cd instanceof ArrayDecoder) {
 153                 int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
 154                 return safeTrim(ca, clen, cs, isTrusted);
 155             } else {
 156                 cd.reset();
 157                 ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
 158                 CharBuffer cb = CharBuffer.wrap(ca);
 159                 try {
 160                     CoderResult cr = cd.decode(bb, cb, true);
 161                     if (!cr.isUnderflow())
 162                         cr.throwException();
 163                     cr = cd.flush(cb);
 164                     if (!cr.isUnderflow())
 165                         cr.throwException();
 166                 } catch (CharacterCodingException x) {
 167                     // Substitution is always enabled,
 168                     // so this shouldn't happen
 169                     throw new Error(x);
 170                 }
 171                 return safeTrim(ca, cb.position(), cs, isTrusted);
 172             }

 173         }
 174     }
 175 
 176     static char[] decode(String charsetName, byte[] ba, int off, int len)
 177         throws UnsupportedEncodingException
 178     {
 179         StringDecoder sd = deref(decoder);
 180         String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
 181         if ((sd == null) || !(csn.equals(sd.requestedCharsetName())
 182                               || csn.equals(sd.charsetName()))) {
 183             sd = null;
 184             try {
 185                 Charset cs = lookupCharset(csn);
 186                 if (cs != null)
 187                     sd = new StringDecoder(cs, csn);
 188             } catch (IllegalCharsetNameException x) {}
 189             if (sd == null)
 190                 throw new UnsupportedEncodingException(csn);
 191             set(decoder, sd);
 192         }
 193         return sd.decode(ba, off, len);
 194     }
 195 
 196     static char[] decode(Charset cs, byte[] ba, int off, int len) {
 197         // (1)We never cache the "external" cs, the only benefit of creating
 198         // an additional StringDe/Encoder object to wrap it is to share the
 199         // de/encode() method. These SD/E objects are short-lifed, the young-gen
 200         // gc should be able to take care of them well. But the best approash
 201         // is still not to generate them if not really necessary.
 202         // (2)The defensive copy of the input byte/char[] has a big performance
 203         // impact, as well as the outgoing result byte/char[]. Need to do the
 204         // optimization check of (sm==null && classLoader0==null) for both.
 205         // (3)getClass().getClassLoader0() is expensive
 206         // (4)There might be a timing gap in isTrusted setting. getClassLoader0()
 207         // is only chcked (and then isTrusted gets set) when (SM==null). It is
 208         // possible that the SM==null for now but then SM is NOT null later
 209         // when safeTrim() is invoked...the "safe" way to do is to redundant
 210         // check (... && (isTrusted || SM == null || getClassLoader0())) in trim
 211         // but it then can be argued that the SM is null when the opertaion
 212         // is started...
 213         CharsetDecoder cd = cs.newDecoder();
 214         int en = scale(len, cd.maxCharsPerByte());
 215         char[] ca = new char[en];
 216         if (len == 0)
 217             return ca;
 218         boolean isTrusted = false;
 219         if (System.getSecurityManager() != null) {
 220             if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
 221                 ba =  Arrays.copyOfRange(ba, off, off + len);
 222                 off = 0;
 223             }
 224         }
 225         if (cd instanceof ArrayDecoder) {
 226             int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
 227             return safeTrim(ca, clen, cs, isTrusted);
 228         } else {
 229             cd.onMalformedInput(CodingErrorAction.REPLACE)
 230               .onUnmappableCharacter(CodingErrorAction.REPLACE)
 231               .reset();
 232             ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
 233             CharBuffer cb = CharBuffer.wrap(ca);
 234             try {
 235                 CoderResult cr = cd.decode(bb, cb, true);
 236                 if (!cr.isUnderflow())
 237                     cr.throwException();
 238                 cr = cd.flush(cb);
 239                 if (!cr.isUnderflow())
 240                     cr.throwException();
 241             } catch (CharacterCodingException x) {
 242                 // Substitution is always enabled,
 243                 // so this shouldn't happen
 244                 throw new Error(x);
 245             }
 246             return safeTrim(ca, cb.position(), cs, isTrusted);
 247         }
 248     }
 249 
 250     static char[] decode(byte[] ba, int off, int len) {
 251         String csn = Charset.defaultCharset().name();
 252         try {
 253             return decode(csn, ba, off, len);
 254         } catch (UnsupportedEncodingException x) {
 255             warnUnsupportedCharset(csn);
 256         }
 257         try {
 258             return decode("ISO-8859-1", ba, off, len);
 259         } catch (UnsupportedEncodingException x) {
 260             // If this code is hit during VM initialization, MessageUtils is
 261             // the only way we will be able to get any kind of error message.
 262             MessageUtils.err("ISO-8859-1 charset not available: "
 263                              + x.toString());
 264             // If we can not find ISO-8859-1 (a required encoding) then things
 265             // are seriously wrong with the installation.
 266             System.exit(1);
 267             return null;
 268         }
 269     }
 270 



 271     // -- Encoding --
 272     private static class StringEncoder {
 273         private Charset cs;
 274         private CharsetEncoder ce;
 275         private final String requestedCharsetName;
 276         private final boolean isTrusted;
 277 
 278         private StringEncoder(Charset cs, String rcn) {
 279             this.requestedCharsetName = rcn;
 280             this.cs = cs;
 281             this.ce = cs.newEncoder()
 282                 .onMalformedInput(CodingErrorAction.REPLACE)
 283                 .onUnmappableCharacter(CodingErrorAction.REPLACE);
 284             this.isTrusted = (cs.getClass().getClassLoader0() == null); 
 285         }
 286 
 287         String charsetName() {
 288             if (cs instanceof HistoricallyNamedCharset)
 289                 return ((HistoricallyNamedCharset)cs).historicalName();
 290             return cs.name();
 291         }
 292 
 293         final String requestedCharsetName() {
 294             return requestedCharsetName;
 295         }
 296 
 297         byte[] encode(char[] ca, int off, int len) {
 298             int en = scale(len, ce.maxBytesPerChar());
 299             byte[] ba = new byte[en];
 300             if (len == 0)
 301                 return ba;
 302             if (ce instanceof ArrayEncoder) {
 303                 int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
 304                 return safeTrim(ba, blen, cs, isTrusted);
 305             } else {
 306                 ce.reset();
 307                 ByteBuffer bb = ByteBuffer.wrap(ba);
 308                 CharBuffer cb = CharBuffer.wrap(ca, off, len);
 309                 try {
 310                     CoderResult cr = ce.encode(cb, bb, true);
 311                     if (!cr.isUnderflow())
 312                         cr.throwException();
 313                     cr = ce.flush(bb);
 314                     if (!cr.isUnderflow())
 315                         cr.throwException();
 316                 } catch (CharacterCodingException x) {
 317                     // Substitution is always enabled,
 318                     // so this shouldn't happen
 319                     throw new Error(x);
 320                 }
 321                 return safeTrim(ba, bb.position(), cs, isTrusted);
 322             }
 323         }
 324     }
 325 
 326     static byte[] encode(String charsetName, char[] ca, int off, int len)
 327         throws UnsupportedEncodingException
 328     {
 329         StringEncoder se = deref(encoder);
 330         String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
 331         if ((se == null) || !(csn.equals(se.requestedCharsetName())
 332                               || csn.equals(se.charsetName()))) {
 333             se = null;
 334             try {
 335                 Charset cs = lookupCharset(csn);
 336                 if (cs != null)
 337                     se = new StringEncoder(cs, csn);
 338             } catch (IllegalCharsetNameException x) {}
 339             if (se == null)
 340                 throw new UnsupportedEncodingException (csn);
 341             set(encoder, se);
 342         }
 343         return se.encode(ca, off, len);
 344     }
 345 
 346     static byte[] encode(Charset cs, char[] ca, int off, int len) {
 347         CharsetEncoder ce = cs.newEncoder();
 348         int en = scale(len, ce.maxBytesPerChar());
 349         byte[] ba = new byte[en];
 350         if (len == 0)
 351             return ba;
 352         boolean isTrusted = false;
 353         if (System.getSecurityManager() != null) {
 354             if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
 355                 ca =  Arrays.copyOfRange(ca, off, off + len);
 356                 off = 0;
 357             }
 358         }
 359         if (ce instanceof ArrayEncoder) {
 360             int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
 361             return safeTrim(ba, blen, cs, isTrusted);
 362         } else {
 363             ce.onMalformedInput(CodingErrorAction.REPLACE)
 364               .onUnmappableCharacter(CodingErrorAction.REPLACE)
 365               .reset();
 366             ByteBuffer bb = ByteBuffer.wrap(ba);
 367             CharBuffer cb = CharBuffer.wrap(ca, off, len);
 368             try {
 369                 CoderResult cr = ce.encode(cb, bb, true);
 370                 if (!cr.isUnderflow())
 371                     cr.throwException();
 372                 cr = ce.flush(bb);
 373                 if (!cr.isUnderflow())
 374                     cr.throwException();
 375             } catch (CharacterCodingException x) {
 376                 throw new Error(x);
 377             }
 378             return safeTrim(ba, bb.position(), cs, isTrusted);
 379         }
 380     }
 381 
 382     static byte[] encode(char[] ca, int off, int len) {
 383         String csn = Charset.defaultCharset().name();
 384         try {
 385             return encode(csn, ca, off, len);
 386         } catch (UnsupportedEncodingException x) {
 387             warnUnsupportedCharset(csn);
 388         }
 389         try {
 390             return encode("ISO-8859-1", ca, off, len);
 391         } catch (UnsupportedEncodingException x) {
 392             // If this code is hit during VM initialization, MessageUtils is
 393             // the only way we will be able to get any kind of error message.
 394             MessageUtils.err("ISO-8859-1 charset not available: "
 395                              + x.toString());
 396             // If we can not find ISO-8859-1 (a required encoding) then things
 397             // are seriously wrong with the installation.
 398             System.exit(1);
 399             return null;
 400         }