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

Print this page




 198         // an additional StringDe/Encoder object to wrap it is to share the
 199         // de/encode() method. These SD/E objects are short-lived, the young-gen
 200         // gc should be able to take care of them well. But the best approach
 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 checked (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 operation
 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         cd.onMalformedInput(CodingErrorAction.REPLACE)
 226           .onUnmappableCharacter(CodingErrorAction.REPLACE)
 227           .reset();
 228         if (cd instanceof ArrayDecoder) {
 229             int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
 230             return safeTrim(ca, clen, cs, isTrusted);
 231         } else {
 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             // use charset name decode() variant which provides caching.
 254             return decode(csn, ba, off, len);
 255         } catch (UnsupportedEncodingException x) {
 256             warnUnsupportedCharset(csn);
 257         }
 258         try {
 259             return decode("ISO-8859-1", ba, off, len);
 260         } catch (UnsupportedEncodingException x) {
 261             // If this code is hit during VM initialization, MessageUtils is
 262             // the only way we will be able to get any kind of error message.
 263             MessageUtils.err("ISO-8859-1 charset not available: "
 264                              + x.toString());
 265             // If we can not find ISO-8859-1 (a required encoding) then things
 266             // are seriously wrong with the installation.
 267             System.exit(1);




 198         // an additional StringDe/Encoder object to wrap it is to share the
 199         // de/encode() method. These SD/E objects are short-lived, the young-gen
 200         // gc should be able to take care of them well. But the best approach
 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 checked (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 operation
 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         
 219         boolean isTrusted = isTrusted(cs);
 220         if (!isTrusted) {
 221             ba =  Arrays.copyOfRange(ba, off, off + len);
 222             off = 0;
 223         }
 224 
 225         setupDecoder(cd);
 226 

 227         if (cd instanceof ArrayDecoder) {
 228             int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
 229             return safeTrim(ca, clen, cs, isTrusted);
 230         } else {
 231             ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
 232             return performDecode(cs, isTrusted, ca, cd, bb);
 233         }
 234     }
 235     
 236     static char[] decode(Charset cs, ByteBuffer bb, int off, int len) {
 237         // See comment at top of decode(Charset,byte[],int,int)
 238         CharsetDecoder cd = cs.newDecoder();
 239         int en = scale(len, cd.maxCharsPerByte());
 240         char[] ca = new char[en];
 241         if (len == 0)
 242             return ca;
 243 
 244         boolean isTrusted = isTrusted(cs);
 245         if (!isTrusted) {
 246             // setup the bytebuffer for copying
 247             ByteBuffer originalByteBuffer = bb;
 248             int originalPosition = originalByteBuffer.position();
 249             int originalLimit = originalByteBuffer.limit();
 250             originalByteBuffer.position(off)
 251                               .limit(off + len);
 252 
 253             // copy the bytebuffer
 254             bb = ByteBuffer.allocateDirect(len)
 255                            .put(originalByteBuffer);
 256             bb.position(0);
 257             
 258             // reset the original bytebuffer
 259             originalByteBuffer.position(originalPosition)
 260                               .limit(originalLimit);
 261 
 262             off = 0;
 263         }
 264 
 265         setupDecoder(cd);
 266 
 267         return performDecode(cs, isTrusted, ca, cd, bb);
 268     }
 269 
 270     private static boolean isTrusted(Charset cs) {
 271       return System.getSecurityManager() != null
 272           && cs.getClass().getClassLoader0() == null;
 273     }
 274 
 275     private static void setupDecoder(CharsetDecoder cd) {
 276         cd.onMalformedInput(CodingErrorAction.REPLACE)
 277           .onUnmappableCharacter(CodingErrorAction.REPLACE)
 278           .reset();
 279     }
 280 
 281     static char[] performDecode(
 282         Charset cs, boolean isTrusted, char[] ca, 
 283         CharsetDecoder cd, ByteBuffer bb) {
 284 
 285         CharBuffer cb = CharBuffer.wrap(ca);
 286         try {
 287             CoderResult cr = cd.decode(bb, cb, true);
 288             if (!cr.isUnderflow())
 289                 cr.throwException();
 290             cr = cd.flush(cb);
 291             if (!cr.isUnderflow())
 292                 cr.throwException();
 293         } catch (CharacterCodingException x) {
 294             // Substitution is always enabled,
 295             // so this shouldn't happen
 296             throw new Error(x);
 297         }
 298         return safeTrim(ca, cb.position(), cs, isTrusted);

 299     }
 300 
 301     static char[] decode(byte[] ba, int off, int len) {
 302         String csn = Charset.defaultCharset().name();
 303         try {
 304             // use charset name decode() variant which provides caching.
 305             return decode(csn, ba, off, len);
 306         } catch (UnsupportedEncodingException x) {
 307             warnUnsupportedCharset(csn);
 308         }
 309         try {
 310             return decode("ISO-8859-1", ba, off, len);
 311         } catch (UnsupportedEncodingException x) {
 312             // If this code is hit during VM initialization, MessageUtils is
 313             // the only way we will be able to get any kind of error message.
 314             MessageUtils.err("ISO-8859-1 charset not available: "
 315                              + x.toString());
 316             // If we can not find ISO-8859-1 (a required encoding) then things
 317             // are seriously wrong with the installation.
 318             System.exit(1);