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

Print this page

        

@@ -213,25 +213,77 @@
         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, 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();

@@ -243,11 +295,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.