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);
 268             return null;


 333                               || csn.equals(se.charsetName()))) {
 334             se = null;
 335             try {
 336                 Charset cs = lookupCharset(csn);
 337                 if (cs != null)
 338                     se = new StringEncoder(cs, csn);
 339             } catch (IllegalCharsetNameException x) {}
 340             if (se == null)
 341                 throw new UnsupportedEncodingException (csn);
 342             set(encoder, se);
 343         }
 344         return se.encode(ca, off, len);
 345     }
 346 
 347     static byte[] encode(Charset cs, char[] ca, int off, int len) {
 348         CharsetEncoder ce = cs.newEncoder();
 349         int en = scale(len, ce.maxBytesPerChar());
 350         byte[] ba = new byte[en];
 351         if (len == 0)
 352             return ba;
 353         boolean isTrusted = false;
 354         if (System.getSecurityManager() != null) {
 355             if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
 356                 ca =  Arrays.copyOfRange(ca, off, off + len);
 357                 off = 0;
 358             }
 359         }
 360         ce.onMalformedInput(CodingErrorAction.REPLACE)
 361           .onUnmappableCharacter(CodingErrorAction.REPLACE)
 362           .reset();
 363         if (ce instanceof ArrayEncoder) {
 364             int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
 365             return safeTrim(ba, blen, cs, isTrusted);
 366         } else {
 367             ByteBuffer bb = ByteBuffer.wrap(ba);
 368             CharBuffer cb = CharBuffer.wrap(ca, off, len);
 369             try {
 370                 CoderResult cr = ce.encode(cb, bb, true);
 371                 if (!cr.isUnderflow())
 372                     cr.throwException();
 373                 cr = ce.flush(bb);
 374                 if (!cr.isUnderflow())
 375                     cr.throwException();
 376             } catch (CharacterCodingException x) {
 377                 throw new Error(x);
 378             }
 379             return safeTrim(ba, bb.position(), cs, isTrusted);
 380         }




























 381     }
 382 
 383     static byte[] encode(char[] ca, int off, int len) {
 384         String csn = Charset.defaultCharset().name();
 385         try {
 386             // use charset name encode() variant which provides caching.
 387             return encode(csn, ca, off, len);
 388         } catch (UnsupportedEncodingException x) {
 389             warnUnsupportedCharset(csn);
 390         }
 391         try {
 392             return encode("ISO-8859-1", ca, off, len);
 393         } catch (UnsupportedEncodingException x) {
 394             // If this code is hit during VM initialization, MessageUtils is
 395             // the only way we will be able to get any kind of error message.
 396             MessageUtils.err("ISO-8859-1 charset not available: "
 397                              + x.toString());
 398             // If we can not find ISO-8859-1 (a required encoding) then things
 399             // are seriously wrong with the installation.
 400             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) {
 237         // See comment at top of decode(Charset,byte[],int,int)
 238         CharsetDecoder cd = cs.newDecoder();
 239         int len = bb.remaining();
 240         int en = scale(len, cd.maxCharsPerByte());
 241         char[] ca = new char[en];
 242         if (len == 0)
 243             return ca;
 244 
 245         boolean isTrusted = isTrusted(cs);
 246         if (!isTrusted) {
 247             // setup the bytebuffer for copying
 248 
 249             // copy the bytebuffer
 250             ByteBuffer originalByteBuffer = bb;
 251             bb = ByteBuffer.allocateDirect(len)
 252                            .put(originalByteBuffer);
 253             bb.position(0);
 254         }
 255 
 256         setupDecoder(cd);
 257 
 258         return performDecode(cs, isTrusted, ca, cd, bb);
 259     }
 260 
 261     private static boolean isTrusted(Charset cs) {
 262         return System.getSecurityManager() != null
 263             // null classloader means the class is on the boot classpath
 264             && cs.getClass().getClassLoader0() == null;
 265     }
 266 
 267     private static void setupDecoder(CharsetDecoder cd) {
 268         cd.onMalformedInput(CodingErrorAction.REPLACE)
 269           .onUnmappableCharacter(CodingErrorAction.REPLACE)
 270           .reset();
 271     }
 272 
 273     static char[] performDecode(
 274         Charset cs, boolean isTrusted, char[] ca, 
 275         CharsetDecoder cd, ByteBuffer bb) {
 276 
 277         CharBuffer cb = CharBuffer.wrap(ca);
 278         try {
 279             CoderResult cr = cd.decode(bb, cb, true);
 280             if (!cr.isUnderflow())
 281                 cr.throwException();
 282             cr = cd.flush(cb);
 283             if (!cr.isUnderflow())
 284                 cr.throwException();
 285         } catch (CharacterCodingException x) {
 286             // Substitution is always enabled,
 287             // so this shouldn't happen
 288             throw new Error(x);
 289         }
 290         return safeTrim(ca, cb.position(), cs, isTrusted);
 291     }

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


 376                               || csn.equals(se.charsetName()))) {
 377             se = null;
 378             try {
 379                 Charset cs = lookupCharset(csn);
 380                 if (cs != null)
 381                     se = new StringEncoder(cs, csn);
 382             } catch (IllegalCharsetNameException x) {}
 383             if (se == null)
 384                 throw new UnsupportedEncodingException (csn);
 385             set(encoder, se);
 386         }
 387         return se.encode(ca, off, len);
 388     }
 389 
 390     static byte[] encode(Charset cs, char[] ca, int off, int len) {
 391         CharsetEncoder ce = cs.newEncoder();
 392         int en = scale(len, ce.maxBytesPerChar());
 393         byte[] ba = new byte[en];
 394         if (len == 0)
 395             return ba;
 396         boolean isTrusted = isTrusted(cs);
 397         if (!isTrusted) {

 398             ca =  Arrays.copyOfRange(ca, off, off + len);
 399             off = 0;
 400         }
 401         setupEncoder(ce);



 402         if (ce instanceof ArrayEncoder) {
 403             int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
 404             return safeTrim(ba, blen, cs, isTrusted);
 405         } else {
 406             ByteBuffer bb = ByteBuffer.wrap(ba);
 407             CharBuffer cb = CharBuffer.wrap(ca, off, len);
 408             try {
 409                 CoderResult cr = ce.encode(cb, bb, true);
 410                 if (!cr.isUnderflow())
 411                     cr.throwException();
 412                 cr = ce.flush(bb);
 413                 if (!cr.isUnderflow())
 414                     cr.throwException();
 415             } catch (CharacterCodingException x) {
 416                 throw new Error(x);
 417             }
 418             return safeTrim(ba, bb.position(), cs, isTrusted);
 419         }
 420     }
 421     
 422     static int encode(Charset cs, char[] ca, int off, int len, byte[] destBuffer, int destOffset) {
 423         ByteBuffer bb = ByteBuffer.wrap(destBuffer, destOffset, destBuffer.length - destOffset);
 424         return encode(cs, ca, off, len, bb);
 425     }
 426 
 427     static int encode(Charset cs, char[] ca, int off, int len, ByteBuffer destBuffer) {
 428         CharsetEncoder ce = cs.newEncoder();
 429         final int originalPosition = destBuffer.position();
 430         CharBuffer cb = CharBuffer.wrap(ca, off, len);
 431         try {
 432             CoderResult cr = ce.encode(cb, destBuffer, true);
 433             if (!cr.isUnderflow())
 434                 cr.throwException();
 435             cr = ce.flush(destBuffer);
 436             if (!cr.isUnderflow())
 437                 cr.throwException();
 438         } catch (CharacterCodingException x) {
 439             throw new Error(x);
 440         }
 441         return destBuffer.position() - originalPosition;
 442     }
 443 
 444     private static void setupEncoder(CharsetEncoder encoder) {
 445         encoder.onMalformedInput(CodingErrorAction.REPLACE)
 446                .onUnmappableCharacter(CodingErrorAction.REPLACE)
 447                .reset();
 448     }
 449 
 450     static byte[] encode(char[] ca, int off, int len) {
 451         String csn = Charset.defaultCharset().name();
 452         try {
 453             // use charset name encode() variant which provides caching.
 454             return encode(csn, ca, off, len);
 455         } catch (UnsupportedEncodingException x) {
 456             warnUnsupportedCharset(csn);
 457         }
 458         try {
 459             return encode("ISO-8859-1", ca, off, len);
 460         } catch (UnsupportedEncodingException x) {
 461             // If this code is hit during VM initialization, MessageUtils is
 462             // the only way we will be able to get any kind of error message.
 463             MessageUtils.err("ISO-8859-1 charset not available: "
 464                              + x.toString());
 465             // If we can not find ISO-8859-1 (a required encoding) then things
 466             // are seriously wrong with the installation.
 467             System.exit(1);