--- old/src/java.base/share/classes/java/lang/StringCoding.java 2014-09-13 14:50:03.661720260 +0100 +++ new/src/java.base/share/classes/java/lang/StringCoding.java 2014-09-13 14:50:03.549720265 +0100 @@ -215,36 +215,87 @@ char[] ca = new char[en]; if (len == 0) return ca; - boolean isTrusted = false; - if (System.getSecurityManager() != null) { - if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) { - ba = Arrays.copyOfRange(ba, off, off + len); - off = 0; - } + + boolean isTrusted = isTrusted(cs); + if (!isTrusted) { + ba = Arrays.copyOfRange(ba, off, off + len); + off = 0; } - cd.onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE) - .reset(); + + setupDecoder(cd); + if (cd instanceof ArrayDecoder) { int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca); return safeTrim(ca, clen, cs, isTrusted); } else { ByteBuffer bb = ByteBuffer.wrap(ba, off, len); - CharBuffer cb = CharBuffer.wrap(ca); - try { - CoderResult cr = cd.decode(bb, cb, true); - if (!cr.isUnderflow()) - cr.throwException(); - cr = cd.flush(cb); - if (!cr.isUnderflow()) - cr.throwException(); - } catch (CharacterCodingException x) { - // Substitution is always enabled, - // so this shouldn't happen - throw new Error(x); - } - return safeTrim(ca, cb.position(), cs, isTrusted); + return performDecode(cs, isTrusted, ca, cd, bb); + } + } + + static char[] decode(Charset cs, ByteBuffer bb, int off, int len) { + // See comment at top of decode(Charset,byte[],int,int) + CharsetDecoder cd = cs.newDecoder(); + int en = scale(len, cd.maxCharsPerByte()); + char[] ca = new char[en]; + if (len == 0) + return ca; + + boolean isTrusted = isTrusted(cs); + if (!isTrusted) { + // setup the bytebuffer for copying + ByteBuffer originalByteBuffer = bb; + int originalPosition = originalByteBuffer.position(); + int originalLimit = originalByteBuffer.limit(); + originalByteBuffer.position(off) + .limit(off + len); + + // copy the bytebuffer + bb = ByteBuffer.allocateDirect(len) + .put(originalByteBuffer); + bb.position(0); + + // reset the original bytebuffer + originalByteBuffer.position(originalPosition) + .limit(originalLimit); + + off = 0; + } + + setupDecoder(cd); + + return performDecode(cs, isTrusted, ca, cd, bb); + } + + private static boolean isTrusted(Charset cs) { + return System.getSecurityManager() != null + && cs.getClass().getClassLoader0() == null; + } + + private static void setupDecoder(CharsetDecoder cd) { + cd.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE) + .reset(); + } + + static char[] performDecode( + Charset cs, boolean isTrusted, char[] ca, + CharsetDecoder cd, ByteBuffer bb) { + + CharBuffer cb = CharBuffer.wrap(ca); + try { + CoderResult cr = cd.decode(bb, cb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = cd.flush(cb); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + // Substitution is always enabled, + // so this shouldn't happen + throw new Error(x); } + return safeTrim(ca, cb.position(), cs, isTrusted); } static char[] decode(byte[] ba, int off, int len) {