--- old/src/java.base/share/classes/java/lang/StringCoding.java 2014-09-25 15:32:01.993804994 +0100 +++ new/src/java.base/share/classes/java/lang/StringCoding.java 2014-09-25 15:32:01.885804999 +0100 @@ -215,36 +215,79 @@ 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) { + // See comment at top of decode(Charset,byte[],int,int) + CharsetDecoder cd = cs.newDecoder(); + int len = bb.limit() - bb.position(); + 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 + + // copy the bytebuffer + ByteBuffer originalByteBuffer = bb; + bb = ByteBuffer.allocateDirect(len) + .put(originalByteBuffer); + bb.position(0); } + + setupDecoder(cd); + + return performDecode(cs, isTrusted, ca, cd, bb); + } + + private static boolean isTrusted(Charset cs) { + return System.getSecurityManager() != null + // null classloader means the class is on the boot classpath + && 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) { @@ -350,16 +393,12 @@ byte[] ba = new byte[en]; if (len == 0) return ba; - boolean isTrusted = false; - if (System.getSecurityManager() != null) { - if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) { - ca = Arrays.copyOfRange(ca, off, off + len); - off = 0; - } + boolean isTrusted = isTrusted(cs); + if (!isTrusted) { + ca = Arrays.copyOfRange(ca, off, off + len); + off = 0; } - ce.onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE) - .reset(); + setupEncoder(ce); if (ce instanceof ArrayEncoder) { int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba); return safeTrim(ba, blen, cs, isTrusted); @@ -379,6 +418,34 @@ return safeTrim(ba, bb.position(), cs, isTrusted); } } + + static int encode(Charset cs, char[] ca, int off, int len, byte[] destBuffer, int destOffset) { + ByteBuffer bb = ByteBuffer.wrap(destBuffer, destOffset, destBuffer.length - destOffset); + return encode(cs, ca, off, len, bb); + } + + static int encode(Charset cs, char[] ca, int off, int len, ByteBuffer destBuffer) { + CharsetEncoder ce = cs.newEncoder(); + final int originalPosition = destBuffer.position(); + CharBuffer cb = CharBuffer.wrap(ca, off, len); + try { + CoderResult cr = ce.encode(cb, destBuffer, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = ce.flush(destBuffer); + if (!cr.isUnderflow()) + cr.throwException(); + } catch (CharacterCodingException x) { + throw new Error(x); + } + return destBuffer.position() - originalPosition; + } + + private static void setupEncoder(CharsetEncoder encoder) { + encoder.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE) + .reset(); + } static byte[] encode(char[] ca, int off, int len) { String csn = Charset.defaultCharset().name();