changeset 6853:e6c3b8e74e50

8007379: Base64.getMimeDecoder().decode() throws IAE for a non-base64 character after padding 8008925: Base64.getMimeDecoder().decode() does not ignore padding chars Summary: updated implementation and spec for corner cases. Reviewed-by: alanb
author sherman
date Tue, 02 Apr 2013 10:12:20 -0700
parents f1b89d4cce82
children 7fbae9125437
files src/share/classes/java/util/Base64.java test/java/util/Base64/TestBase64.java
diffstat 2 files changed, 21 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/Base64.java	Tue Apr 02 10:32:21 2013 +0200
+++ b/src/share/classes/java/util/Base64.java	Tue Apr 02 10:12:20 2013 -0700
@@ -620,7 +620,10 @@
      * required. So if the final unit of the encoded byte data only has
      * two or three Base64 characters (without the corresponding padding
      * character(s) padded), they are decoded as if followed by padding
-     * character(s).
+     * character(s). If there is padding character present in the
+     * final unit, the correct number of padding character(s) must be
+     * present, otherwise {@code IllegalArgumentException} is thrown
+     * during decoding.
      *
      * <p> Instances of {@link Decoder} class are safe for use by
      * multiple concurrent threads.
@@ -1034,23 +1037,26 @@
                 throw new IllegalArgumentException(
                     "Input byte[] should at least have 2 bytes for base64 bytes");
             }
-            if (src[sl - 1] == '=') {
-                paddings++;
-                if (src[sl - 2] == '=')
-                    paddings++;
-            }
             if (isMIME) {
                 // scan all bytes to fill out all non-alphabet. a performance
                 // trade-off of pre-scan or Arrays.copyOf
                 int n = 0;
                 while (sp < sl) {
                     int b = src[sp++] & 0xff;
-                    if (b == '=')
+                    if (b == '=') {
+                        len -= (sl - sp + 1);
                         break;
+                    }
                     if ((b = base64[b]) == -1)
                         n++;
                 }
                 len -= n;
+            } else {
+                if (src[sl - 1] == '=') {
+                    paddings++;
+                    if (src[sl - 2] == '=')
+                        paddings++;
+                }
             }
             if (paddings == 0 && (len & 0x3) !=  0)
                 paddings = 4 - (len & 0x3);
--- a/test/java/util/Base64/TestBase64.java	Tue Apr 02 10:32:21 2013 +0200
+++ b/test/java/util/Base64/TestBase64.java	Tue Apr 02 10:12:20 2013 -0700
@@ -22,7 +22,7 @@
  */
 
 /**
- * @test 4235519 8004212 8005394 8007298 8006295 8006315 8006530
+ * @test 4235519 8004212 8005394 8007298 8006295 8006315 8006530 8007379 8008925
  * @summary tests java.util.Base64
  */
 
@@ -107,6 +107,9 @@
         checkIAE(new Runnable() { public void run() {
             Base64.getDecoder().decode(ByteBuffer.wrap(decoded), ByteBuffer.allocateDirect(1024)); }});
 
+        // illegal ending unit
+        checkIAE(new Runnable() { public void run() { Base64.getMimeDecoder().decode("$=#"); }});
+
         // test return value from decode(ByteBuffer, ByteBuffer)
         testDecBufRet();
 
@@ -115,7 +118,6 @@
 
         // test decoding of unpadded data
         testDecodeUnpadded();
-
         // test mime decoding with ignored character after padding
         testDecodeIgnoredAfterPadding();
     }
@@ -384,6 +386,10 @@
                 encoded = Arrays.copyOf(encoded, encoded.length + 1);
                 encoded[encoded.length - 1] = nonBase64;
                 checkEqual(decM.decode(encoded), src[i], "Non-base64 char is not ignored");
+                byte[] decoded = new byte[src[i].length];
+                decM.decode(encoded, decoded);
+                checkEqual(decoded, src[i], "Non-base64 char is not ignored");
+
                 try {
                     dec.decode(encoded);
                     throw new RuntimeException("No IAE for non-base64 char");