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

Print this page

        

@@ -213,25 +213,69 @@
         CharsetDecoder cd = cs.newDecoder();
         int en = scale(len, cd.maxCharsPerByte());
         char[] ca = new char[en];
         if (len == 0)
             return ca;
-        boolean isTrusted = false;
-        if (System.getSecurityManager() != null) {
-            if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
+        
+        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);
+            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.remaining();
+        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();

@@ -243,11 +287,10 @@
                 // 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) {
         String csn = Charset.defaultCharset().name();
         try {
             // use charset name decode() variant which provides caching.

@@ -348,20 +391,16 @@
         CharsetEncoder ce = cs.newEncoder();
         int en = scale(len, ce.maxBytesPerChar());
         byte[] ba = new byte[en];
         if (len == 0)
             return ba;
-        boolean isTrusted = false;
-        if (System.getSecurityManager() != null) {
-            if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
+        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);
         } else {
             ByteBuffer bb = ByteBuffer.wrap(ba);

@@ -378,10 +417,38 @@
             }
             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();
         try {
             // use charset name encode() variant which provides caching.
             return encode(csn, ca, off, len);