6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /**
25 * @test 4235519 8004212 8005394 8007298 8006295 8006315 8006530 8007379 8008925
26 * 8014217 8025003 8026330
27 * @summary tests java.util.Base64
28 */
29
30 import java.io.ByteArrayInputStream;
31 import java.io.ByteArrayOutputStream;
32 import java.io.InputStream;
33 import java.io.IOException;
34 import java.io.OutputStream;
35 import java.nio.ByteBuffer;
36 import java.util.Arrays;
37 import java.util.Base64;
38 import java.util.Random;
39
40 public class TestBase64 {
41
42 public static void main(String args[]) throws Throwable {
43 int numRuns = 10;
44 int numBytes = 200;
45 if (args.length > 1) {
46 numRuns = Integer.parseInt(args[0]);
75 testNull(Base64.getDecoder());
76 testNull(Base64.getUrlDecoder());
77 testNull(Base64.getMimeDecoder());
78 checkNull(new Runnable() { public void run() { Base64.getMimeEncoder(10, null); }});
79
80 testIOE(Base64.getEncoder());
81 testIOE(Base64.getUrlEncoder());
82 testIOE(Base64.getMimeEncoder());
83 testIOE(Base64.getMimeEncoder(10, new byte[]{'\n'}));
84
85 byte[] src = new byte[1024];
86 new Random().nextBytes(src);
87 final byte[] decoded = Base64.getEncoder().encode(src);
88 testIOE(Base64.getDecoder(), decoded);
89 testIOE(Base64.getMimeDecoder(), decoded);
90 testIOE(Base64.getUrlDecoder(), Base64.getUrlEncoder().encode(src));
91
92 // illegal line separator
93 checkIAE(new Runnable() { public void run() { Base64.getMimeEncoder(10, new byte[]{'\r', 'N'}); }});
94
95 // illegal base64 character
96 decoded[2] = (byte)0xe0;
97 checkIAE(new Runnable() {
98 public void run() { Base64.getDecoder().decode(decoded); }});
99 checkIAE(new Runnable() {
100 public void run() { Base64.getDecoder().decode(decoded, new byte[1024]); }});
101 checkIAE(new Runnable() { public void run() {
102 Base64.getDecoder().decode(ByteBuffer.wrap(decoded)); }});
103 checkIAE(new Runnable() { public void run() {
104 Base64.getDecoder().decode(ByteBuffer.wrap(decoded), ByteBuffer.allocate(1024)); }});
105 checkIAE(new Runnable() { public void run() {
106 Base64.getDecoder().decode(ByteBuffer.wrap(decoded), ByteBuffer.allocateDirect(1024)); }});
107
108 // illegal ending unit
109 checkIOE(new Testable() { public void test() throws IOException {
110 byte[] bytes = "AA=".getBytes("ASCII");
111 try (InputStream stream =
112 Base64.getDecoder().wrap(new ByteArrayInputStream(bytes))) {
113 while (stream.read() != -1);
114 }
115 }});
116
117 // test return value from decode(ByteBuffer, ByteBuffer)
118 testDecBufRet();
119
120 // test single-non-base64 character for mime decoding
121 testSingleNonBase64MimeDec();
122
123 // test decoding of unpadded data
124 testDecodeUnpadded();
125 // test mime decoding with ignored character after padding
126 testDecodeIgnoredAfterPadding();
127
128 // lenient mode for ending unit
129 testLenientPadding();
130
131 }
132
133 private static sun.misc.BASE64Encoder sunmisc = new sun.misc.BASE64Encoder();
134
135 private static void test(Base64.Encoder enc, Base64.Decoder dec,
136 int numRuns, int numBytes) throws Throwable {
137 Random rnd = new java.util.Random();
138
139 enc.encode(new byte[0]);
140 dec.decode(new byte[0]);
141
142 for (boolean withoutPadding : new boolean[] { false, true}) {
143 if (withoutPadding) {
144 enc = enc.withoutPadding();
145 }
146 for (int i=0; i<numRuns; i++) {
147 for (int j=1; j<numBytes; j++) {
148 byte[] orig = new byte[j];
149 rnd.nextBytes(orig);
150
185
186 if (encoded2 != null) {
187 buf = dec.decode(new String(encoded2, "ASCII"));
188 checkEqual(buf, orig, "Base64 decoding(String) failed!");
189 }
190
191 //-------- testing encode/decode(Buffer)--------
192 testEncode(enc, ByteBuffer.wrap(orig), encoded);
193 ByteBuffer bin = ByteBuffer.allocateDirect(orig.length);
194 bin.put(orig).flip();
195 testEncode(enc, bin, encoded);
196
197 testDecode(dec, ByteBuffer.wrap(encoded), orig);
198 bin = ByteBuffer.allocateDirect(encoded.length);
199 bin.put(encoded).flip();
200 testDecode(dec, bin, orig);
201
202 if (encoded2 != null)
203 testDecode(dec, ByteBuffer.wrap(encoded2), orig);
204
205 // -------- testing encode(Buffer, Buffer)--------
206 testEncode(enc, encoded,
207 ByteBuffer.wrap(orig),
208 ByteBuffer.allocate(encoded.length + 10));
209
210 testEncode(enc, encoded,
211 ByteBuffer.wrap(orig),
212 ByteBuffer.allocateDirect(encoded.length + 10));
213
214 // --------testing decode(Buffer, Buffer);--------
215 testDecode(dec, orig,
216 ByteBuffer.wrap(encoded),
217 ByteBuffer.allocate(orig.length + 10));
218
219 testDecode(dec, orig,
220 ByteBuffer.wrap(encoded),
221 ByteBuffer.allocateDirect(orig.length + 10));
222
223 // --------testing decode.wrap(input stream)--------
224 // 1) random buf length
225 ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
226 InputStream is = dec.wrap(bais);
227 buf = new byte[orig.length + 10];
228 int len = orig.length;
229 int off = 0;
230 while (true) {
231 int n = rnd.nextInt(len);
232 if (n == 0)
233 n = 1;
234 n = is.read(buf, off, n);
235 if (n == -1) {
236 checkEqual(off, orig.length,
237 "Base64 stream decoding failed");
238 break;
239 }
240 off += n;
241 len -= n;
242 if (len == 0)
305 "Base64 enc.encode(src, null) returns wrong size!");
306 buf = Arrays.copyOf(buf, ret);
307 checkEqual(buf, orig,
308 "Base64 dec.decode(src, dst) failed!");
309
310 }
311 }
312 }
313 }
314
315 private static final byte[] ba_null = null;
316 private static final String str_null = null;
317 private static final ByteBuffer bb_null = null;
318
319 private static void testNull(final Base64.Encoder enc) {
320 checkNull(new Runnable() { public void run() { enc.encode(ba_null); }});
321 checkNull(new Runnable() { public void run() { enc.encodeToString(ba_null); }});
322 checkNull(new Runnable() { public void run() { enc.encode(ba_null, new byte[10]); }});
323 checkNull(new Runnable() { public void run() { enc.encode(new byte[10], ba_null); }});
324 checkNull(new Runnable() { public void run() { enc.encode(bb_null); }});
325 checkNull(new Runnable() { public void run() { enc.encode(bb_null, ByteBuffer.allocate(10), 0); }});
326 checkNull(new Runnable() { public void run() { enc.encode(ByteBuffer.allocate(10), bb_null, 0); }});
327 checkNull(new Runnable() { public void run() { enc.wrap(null); }});
328 }
329
330 private static void testNull(final Base64.Decoder dec) {
331 checkNull(new Runnable() { public void run() { dec.decode(ba_null); }});
332 checkNull(new Runnable() { public void run() { dec.decode(str_null); }});
333 checkNull(new Runnable() { public void run() { dec.decode(ba_null, new byte[10]); }});
334 checkNull(new Runnable() { public void run() { dec.decode(new byte[10], ba_null); }});
335 checkNull(new Runnable() { public void run() { dec.decode(bb_null); }});
336 checkNull(new Runnable() { public void run() { dec.decode(bb_null, ByteBuffer.allocate(10)); }});
337 checkNull(new Runnable() { public void run() { dec.decode(ByteBuffer.allocate(10), bb_null); }});
338 checkNull(new Runnable() { public void run() { dec.wrap(null); }});
339 }
340
341 private static interface Testable {
342 public void test() throws Throwable;
343 }
344
345 private static void testIOE(final Base64.Encoder enc) throws Throwable {
346 ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
347 final OutputStream os = enc.wrap(baos);
348 os.write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9});
349 os.close();
350 checkIOE(new Testable() { public void test() throws Throwable { os.write(10); }});
351 checkIOE(new Testable() { public void test() throws Throwable { os.write(new byte[] {10}); }});
352 checkIOE(new Testable() { public void test() throws Throwable { os.write(new byte[] {10}, 1, 4); }});
353 }
354
355 private static void testIOE(final Base64.Decoder dec, byte[] decoded) throws Throwable {
356 ByteArrayInputStream bais = new ByteArrayInputStream(decoded);
357 final InputStream is = dec.wrap(bais);
358 is.read(new byte[10]);
395 "ABCDE".getBytes("ascii")
396 };
397 Base64.Encoder encM = Base64.getMimeEncoder();
398 Base64.Decoder decM = Base64.getMimeDecoder();
399 Base64.Encoder enc = Base64.getEncoder();
400 Base64.Decoder dec = Base64.getDecoder();
401 for (int i = 0; i < src.length; i++) {
402 // decode(byte[])
403 byte[] encoded = encM.encode(src[i]);
404 encoded = Arrays.copyOf(encoded, encoded.length + 1);
405 encoded[encoded.length - 1] = nonBase64;
406 checkEqual(decM.decode(encoded), src[i], "Non-base64 char is not ignored");
407 byte[] decoded = new byte[src[i].length];
408 decM.decode(encoded, decoded);
409 checkEqual(decoded, src[i], "Non-base64 char is not ignored");
410
411 try {
412 dec.decode(encoded);
413 throw new RuntimeException("No IAE for non-base64 char");
414 } catch (IllegalArgumentException iae) {}
415
416 // decode(ByteBuffer[], ByteBuffer[])
417 ByteBuffer encodedBB = ByteBuffer.wrap(encoded);
418 ByteBuffer decodedBB = ByteBuffer.allocate(100);
419 int ret = decM.decode(encodedBB, decodedBB);
420 byte[] buf = new byte[ret];
421 decodedBB.flip();
422 decodedBB.get(buf);
423 checkEqual(buf, src[i], "Non-base64 char is not ignored");
424 try {
425 encodedBB.rewind();
426 decodedBB.clear();
427 dec.decode(encodedBB, decodedBB);
428 throw new RuntimeException("No IAE for non-base64 char");
429 } catch (IllegalArgumentException iae) {}
430 // direct
431 encodedBB.rewind();
432 decodedBB = ByteBuffer.allocateDirect(100);
433 ret = decM.decode(encodedBB, decodedBB);
434 buf = new byte[ret];
435 decodedBB.flip();
436 decodedBB.get(buf);
437 checkEqual(buf, src[i], "Non-base64 char is not ignored");
438 try {
439 encodedBB.rewind();
440 decodedBB.clear();
441 dec.decode(encodedBB, decodedBB);
442 throw new RuntimeException("No IAE for non-base64 char");
443 } catch (IllegalArgumentException iae) {}
444 }
445 }
446 }
447
448 private static void testLenientPadding() throws Throwable {
449 String[] data = new String[] {
450 "=", "", // unnecessary padding
451 "QUJD=", "ABC", //"ABC".encode() -> "QUJD"
452
453 "QQ=", "A", // incomplete padding
454 "QQ=N", "A", // incorrect padding
455 "QQ=?", "A",
456 "QUJDQQ=", "ABCA",
457 "QUJDQQ=N", "ABCA",
458 "QUJDQQ=?", "ABCA",
459
460 "QUI=X", "AB", // incorrect padding
461 "QUI=?", "AB", // incorrect padding
462 };
463 Base64.Decoder dec = Base64.getMimeDecoder();
464
465 for (int i = 0; i < data.length; i += 2) {
466 byte[] src = data[i].getBytes("ASCII");
467 byte[] expected = data[i + 1].getBytes("ASCII");
468 // decode(byte[])
469 byte[] ret = dec.decode(src);
470 checkEqual(ret, expected, "lenient padding decoding failed!");
471
472 // decode(String)
473 ret = dec.decode(data[i]);
474 checkEqual(ret, expected, "lenient padding decoding failed!");
475
476 // decode(ByteBuffer)
477 ByteBuffer srcBB = ByteBuffer.wrap(src);
478 ByteBuffer retBB = dec.decode(srcBB);
479 checkEqual(srcBB.remaining(), 0, "lenient padding decoding failed!");
480 checkEqual(Arrays.copyOf(retBB.array(), retBB.remaining()),
481 expected, "lenient padding decoding failed!");
482
483 // wrap.decode(byte[])
484 ret = new byte[10];
485 int n = dec.wrap(new ByteArrayInputStream(src)).read(ret);
486 checkEqual(Arrays.copyOf(ret, n), expected, "lenient padding decoding failed!");
487 }
488 }
489
490 private static void testDecodeUnpadded() throws Throwable {
491 byte[] srcA = new byte[] { 'Q', 'Q' };
492 byte[] srcAA = new byte[] { 'Q', 'Q', 'E'};
493 Base64.Decoder dec = Base64.getDecoder();
494 byte[] ret = dec.decode(srcA);
495 if (ret[0] != 'A')
496 throw new RuntimeException("Decoding unpadding input A failed");
497 ret = dec.decode(srcAA);
498 if (ret[0] != 'A' && ret[1] != 'A')
499 throw new RuntimeException("Decoding unpadding input AA failed");
500 ret = new byte[10];
501 if (dec.wrap(new ByteArrayInputStream(srcA)).read(ret) != 1 &&
502 ret[0] != 'A')
503 throw new RuntimeException("Decoding unpadding input A from stream failed");
504 if (dec.wrap(new ByteArrayInputStream(srcA)).read(ret) != 2 &&
505 ret[0] != 'A' && ret[1] != 'A')
506 throw new RuntimeException("Decoding unpadding input AA from stream failed");
507 }
508
509 // single-non-base64-char should be ignored for mime decoding, but
510 // iae for basic decoding
511 private static void testSingleNonBase64MimeDec() throws Throwable {
512 for (String nonBase64 : new String[] {"#", "(", "!", "\\", "-", "_"}) {
513 if (Base64.getMimeDecoder().decode(nonBase64).length != 0) {
514 throw new RuntimeException("non-base64 char is not ignored");
515 }
516 try {
517 Base64.getDecoder().decode(nonBase64);
518 throw new RuntimeException("No IAE for single non-base64 char");
519 } catch (IllegalArgumentException iae) {}
520 }
521 }
522
523 private static void testDecBufRet() throws Throwable {
524 Random rnd = new java.util.Random();
525 Base64.Encoder encoder = Base64.getEncoder();
526 Base64.Decoder decoder = Base64.getDecoder();
527 // src pos, len expected
528 int[][] tests = { { 6, 3, 3, 3}, // xxx xxx -> yyyy yyyy
529 { 6, 3, 4, 3},
530 { 6, 3, 5, 3},
531 { 6, 3, 6, 6},
532 { 6, 11, 4, 3},
533 { 6, 11, 4, 3},
534 { 6, 11, 5, 3},
535 { 6, 11, 6, 6},
536 { 7, 3, 6, 6}, // xxx xxx x -> yyyy yyyy yy==
537 { 7, 3, 7, 7},
538 { 7, 11, 6, 6},
539 { 7, 11, 7, 7},
540 { 8, 3, 6, 6}, // xxx xxx xx -> yyyy yyyy yyy=
541 { 8, 3, 7, 6},
542 { 8, 3, 8, 8},
543 { 8, 13, 6, 6},
544 { 8, 13, 7, 6},
545 { 8, 13, 8, 8},
546
547 };
548 ByteBuffer dstBuf = ByteBuffer.allocate(100);
549 for (boolean direct : new boolean[] { false, true}) {
550 for (int[] test : tests) {
551 byte[] src = new byte[test[0]];
552 rnd.nextBytes(src);
553 ByteBuffer srcBuf = direct ? ByteBuffer.allocate(100)
554 : ByteBuffer.allocateDirect(100);
555 srcBuf.put(encoder.encode(src)).flip();
556 dstBuf.clear().position(test[1]).limit(test[1]+ test[2]);
557 int ret = decoder.decode(srcBuf, dstBuf);
558 if (ret != test[3]) {
559 System.out.printf(" [%6s] src=%d, pos=%d, len=%d, expected=%d, ret=%d%n",
560 direct?"direct":"",
561 test[0], test[1], test[2], test[3], ret);
562 throw new RuntimeException("ret != expected");
563 }
564 }
565 }
566 }
567
568 private static final void testEncode(Base64.Encoder enc, ByteBuffer bin, byte[] expected)
569 throws Throwable {
570
571 ByteBuffer bout = enc.encode(bin);
572 byte[] buf = new byte[bout.remaining()];
573 bout.get(buf);
574 if (bin.hasRemaining()) {
575 throw new RuntimeException(
576 "Base64 enc.encode(ByteBuffer) failed!");
577 }
578 checkEqual(buf, expected, "Base64 enc.encode(bf, bf) failed!");
579 }
580
581 private static final void testDecode(Base64.Decoder dec, ByteBuffer bin, byte[] expected)
582 throws Throwable {
583
584 ByteBuffer bout = dec.decode(bin);
585 byte[] buf = new byte[bout.remaining()];
586 bout.get(buf);
587 checkEqual(buf, expected, "Base64 dec.decode(bf) failed!");
588 }
589
590 private static final void testEncode(Base64.Encoder enc, byte[] expected,
591 ByteBuffer ibb, ByteBuffer obb)
592 throws Throwable {
593 Random rnd = new Random();
594 int bytesOut = enc.encode(ibb, obb, 0);
595 if (ibb.hasRemaining()) {
596 throw new RuntimeException(
597 "Base64 enc.encode(bf, bf) failed with wrong return!");
598 }
599 obb.flip();
600 byte[] buf = new byte[obb.remaining()];
601 obb.get(buf);
602 checkEqual(buf, expected, "Base64 enc.encode(bf, bf) failed!");
603 ibb.rewind();
604 obb.position(0);
605 obb.limit(0);
606 bytesOut = 0;
607
608 do { // increase the "limit" incrementally & randomly
609 int n = rnd.nextInt(expected.length - obb.position());
610 if (n == 0)
611 n = 1;
612 obb.limit(obb.limit() + n);
613 //obb.limit(Math.min(obb.limit() + n, expected.length));
614 bytesOut = enc.encode(ibb, obb, bytesOut);
615 } while (ibb.hasRemaining());
616 obb.flip();
617 buf = new byte[obb.remaining()];
618 obb.get(buf);
619 checkEqual(buf, expected, "Base64 enc.encode(bf, bf) failed!");
620 }
621
622 private static final void testDecode(Base64.Decoder dec, byte[] expected,
623 ByteBuffer ibb, ByteBuffer obb)
624 throws Throwable {
625 Random rnd = new Random();
626
627 dec.decode(ibb, obb);
628 if (ibb.hasRemaining()) {
629 throw new RuntimeException(
630 "Base64 dec.decode(bf, bf) failed with un-decoded ibb!");
631 }
632 obb.flip();
633 byte[] buf = new byte[obb.remaining()];
634 obb.get(buf);
635 checkEqual(buf, expected, "Base64 dec.decode(bf, bf) failed!");
636
637 ibb.rewind();
638 obb.position(0);
639 obb.limit(0);
640 do { // increase the "limit" incrementally & randomly
641 int n = rnd.nextInt(expected.length - obb.position());
642 if (n == 0)
643 n = 1;
644 obb.limit(obb.limit() + n);
645 dec.decode(ibb, obb);
646 } while (ibb.hasRemaining());
647
648
649 obb.flip();
650 buf = new byte[obb.remaining()];
651 obb.get(buf);
652 checkEqual(buf, expected, "Base64 dec.decode(bf, bf) failed!");
653 }
654
655 private static final void checkEqual(int v1, int v2, String msg)
656 throws Throwable {
657 if (v1 != v2) {
658 System.out.printf(" v1=%d%n", v1);
659 System.out.printf(" v2=%d%n", v2);
660 throw new RuntimeException(msg);
661 }
662 }
663
664 private static final void checkEqual(byte[] r1, byte[] r2, String msg)
665 throws Throwable {
666 if (!Arrays.equals(r1, r2)) {
667 System.out.printf(" r1[%d]=[%s]%n", r1.length, new String(r1));
668 System.out.printf(" r2[%d]=[%s]%n", r2.length, new String(r2));
669 throw new RuntimeException(msg);
670 }
671 }
672
673 // remove line feeds,
674 private static final byte[] normalize(byte[] src) {
|
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /**
25 * @test 4235519 8004212 8005394 8007298 8006295 8006315 8006530 8007379 8008925
26 * 8014217 8025003 8026330 8028397
27 * @summary tests java.util.Base64
28 */
29
30 import java.io.ByteArrayInputStream;
31 import java.io.ByteArrayOutputStream;
32 import java.io.InputStream;
33 import java.io.IOException;
34 import java.io.OutputStream;
35 import java.nio.ByteBuffer;
36 import java.util.Arrays;
37 import java.util.Base64;
38 import java.util.Random;
39
40 public class TestBase64 {
41
42 public static void main(String args[]) throws Throwable {
43 int numRuns = 10;
44 int numBytes = 200;
45 if (args.length > 1) {
46 numRuns = Integer.parseInt(args[0]);
75 testNull(Base64.getDecoder());
76 testNull(Base64.getUrlDecoder());
77 testNull(Base64.getMimeDecoder());
78 checkNull(new Runnable() { public void run() { Base64.getMimeEncoder(10, null); }});
79
80 testIOE(Base64.getEncoder());
81 testIOE(Base64.getUrlEncoder());
82 testIOE(Base64.getMimeEncoder());
83 testIOE(Base64.getMimeEncoder(10, new byte[]{'\n'}));
84
85 byte[] src = new byte[1024];
86 new Random().nextBytes(src);
87 final byte[] decoded = Base64.getEncoder().encode(src);
88 testIOE(Base64.getDecoder(), decoded);
89 testIOE(Base64.getMimeDecoder(), decoded);
90 testIOE(Base64.getUrlDecoder(), Base64.getUrlEncoder().encode(src));
91
92 // illegal line separator
93 checkIAE(new Runnable() { public void run() { Base64.getMimeEncoder(10, new byte[]{'\r', 'N'}); }});
94
95 // malformed padding/ending
96 testMalformedPadding();
97
98 // illegal base64 character
99 decoded[2] = (byte)0xe0;
100 checkIAE(new Runnable() {
101 public void run() { Base64.getDecoder().decode(decoded); }});
102 checkIAE(new Runnable() {
103 public void run() { Base64.getDecoder().decode(decoded, new byte[1024]); }});
104 checkIAE(new Runnable() { public void run() {
105 Base64.getDecoder().decode(ByteBuffer.wrap(decoded)); }});
106
107 // test single-non-base64 character for mime decoding
108 testSingleNonBase64MimeDec();
109
110 // test decoding of unpadded data
111 testDecodeUnpadded();
112
113 // test mime decoding with ignored character after padding
114 testDecodeIgnoredAfterPadding();
115 }
116
117 private static sun.misc.BASE64Encoder sunmisc = new sun.misc.BASE64Encoder();
118
119 private static void test(Base64.Encoder enc, Base64.Decoder dec,
120 int numRuns, int numBytes) throws Throwable {
121 Random rnd = new java.util.Random();
122
123 enc.encode(new byte[0]);
124 dec.decode(new byte[0]);
125
126 for (boolean withoutPadding : new boolean[] { false, true}) {
127 if (withoutPadding) {
128 enc = enc.withoutPadding();
129 }
130 for (int i=0; i<numRuns; i++) {
131 for (int j=1; j<numBytes; j++) {
132 byte[] orig = new byte[j];
133 rnd.nextBytes(orig);
134
169
170 if (encoded2 != null) {
171 buf = dec.decode(new String(encoded2, "ASCII"));
172 checkEqual(buf, orig, "Base64 decoding(String) failed!");
173 }
174
175 //-------- testing encode/decode(Buffer)--------
176 testEncode(enc, ByteBuffer.wrap(orig), encoded);
177 ByteBuffer bin = ByteBuffer.allocateDirect(orig.length);
178 bin.put(orig).flip();
179 testEncode(enc, bin, encoded);
180
181 testDecode(dec, ByteBuffer.wrap(encoded), orig);
182 bin = ByteBuffer.allocateDirect(encoded.length);
183 bin.put(encoded).flip();
184 testDecode(dec, bin, orig);
185
186 if (encoded2 != null)
187 testDecode(dec, ByteBuffer.wrap(encoded2), orig);
188
189 // --------testing decode.wrap(input stream)--------
190 // 1) random buf length
191 ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
192 InputStream is = dec.wrap(bais);
193 buf = new byte[orig.length + 10];
194 int len = orig.length;
195 int off = 0;
196 while (true) {
197 int n = rnd.nextInt(len);
198 if (n == 0)
199 n = 1;
200 n = is.read(buf, off, n);
201 if (n == -1) {
202 checkEqual(off, orig.length,
203 "Base64 stream decoding failed");
204 break;
205 }
206 off += n;
207 len -= n;
208 if (len == 0)
271 "Base64 enc.encode(src, null) returns wrong size!");
272 buf = Arrays.copyOf(buf, ret);
273 checkEqual(buf, orig,
274 "Base64 dec.decode(src, dst) failed!");
275
276 }
277 }
278 }
279 }
280
281 private static final byte[] ba_null = null;
282 private static final String str_null = null;
283 private static final ByteBuffer bb_null = null;
284
285 private static void testNull(final Base64.Encoder enc) {
286 checkNull(new Runnable() { public void run() { enc.encode(ba_null); }});
287 checkNull(new Runnable() { public void run() { enc.encodeToString(ba_null); }});
288 checkNull(new Runnable() { public void run() { enc.encode(ba_null, new byte[10]); }});
289 checkNull(new Runnable() { public void run() { enc.encode(new byte[10], ba_null); }});
290 checkNull(new Runnable() { public void run() { enc.encode(bb_null); }});
291 checkNull(new Runnable() { public void run() { enc.wrap((OutputStream)null); }});
292 }
293
294 private static void testNull(final Base64.Decoder dec) {
295 checkNull(new Runnable() { public void run() { dec.decode(ba_null); }});
296 checkNull(new Runnable() { public void run() { dec.decode(str_null); }});
297 checkNull(new Runnable() { public void run() { dec.decode(ba_null, new byte[10]); }});
298 checkNull(new Runnable() { public void run() { dec.decode(new byte[10], ba_null); }});
299 checkNull(new Runnable() { public void run() { dec.decode(bb_null); }});
300 checkNull(new Runnable() { public void run() { dec.wrap((InputStream)null); }});
301 }
302
303 private static interface Testable {
304 public void test() throws Throwable;
305 }
306
307 private static void testIOE(final Base64.Encoder enc) throws Throwable {
308 ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
309 final OutputStream os = enc.wrap(baos);
310 os.write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9});
311 os.close();
312 checkIOE(new Testable() { public void test() throws Throwable { os.write(10); }});
313 checkIOE(new Testable() { public void test() throws Throwable { os.write(new byte[] {10}); }});
314 checkIOE(new Testable() { public void test() throws Throwable { os.write(new byte[] {10}, 1, 4); }});
315 }
316
317 private static void testIOE(final Base64.Decoder dec, byte[] decoded) throws Throwable {
318 ByteArrayInputStream bais = new ByteArrayInputStream(decoded);
319 final InputStream is = dec.wrap(bais);
320 is.read(new byte[10]);
357 "ABCDE".getBytes("ascii")
358 };
359 Base64.Encoder encM = Base64.getMimeEncoder();
360 Base64.Decoder decM = Base64.getMimeDecoder();
361 Base64.Encoder enc = Base64.getEncoder();
362 Base64.Decoder dec = Base64.getDecoder();
363 for (int i = 0; i < src.length; i++) {
364 // decode(byte[])
365 byte[] encoded = encM.encode(src[i]);
366 encoded = Arrays.copyOf(encoded, encoded.length + 1);
367 encoded[encoded.length - 1] = nonBase64;
368 checkEqual(decM.decode(encoded), src[i], "Non-base64 char is not ignored");
369 byte[] decoded = new byte[src[i].length];
370 decM.decode(encoded, decoded);
371 checkEqual(decoded, src[i], "Non-base64 char is not ignored");
372
373 try {
374 dec.decode(encoded);
375 throw new RuntimeException("No IAE for non-base64 char");
376 } catch (IllegalArgumentException iae) {}
377 }
378 }
379 }
380
381 private static void testMalformedPadding() throws Throwable {
382 Object[] data = new Object[] {
383 "$=#", "", 0, // illegal ending unit
384 "A", "", 0, // dangling single byte
385 "A=", "", 0,
386 "A==", "", 0,
387 "QUJDA", "ABC", 4,
388 "QUJDA=", "ABC", 4,
389 "QUJDA==", "ABC", 4,
390
391 "=", "", 0, // unnecessary padding
392 "QUJD=", "ABC", 4, //"ABC".encode() -> "QUJD"
393
394 "AA=", "", 0, // incomplete padding
395 "QQ=", "", 0,
396 "QQ=N", "", 0, // incorrect padding
397 "QQ=?", "", 0,
398 "QUJDQQ=", "ABC", 4,
399 "QUJDQQ=N", "ABC", 4,
400 "QUJDQQ=?", "ABC", 4,
401 };
402
403 Base64.Decoder[] decs = new Base64.Decoder[] {
404 Base64.getDecoder(),
405 Base64.getUrlDecoder(),
406 Base64.getMimeDecoder()
407 };
408
409 for (Base64.Decoder dec : decs) {
410 for (int i = 0; i < data.length; i += 3) {
411 final String srcStr = (String)data[i];
412 final byte[] srcBytes = srcStr.getBytes("ASCII");
413 final ByteBuffer srcBB = ByteBuffer.wrap(srcBytes);
414 byte[] expected = ((String)data[i + 1]).getBytes("ASCII");
415 int pos = (Integer)data[i + 2];
416
417 // decode(byte[])
418 checkIAE(new Runnable() { public void run() { dec.decode(srcBytes); }});
419
420 // decode(String)
421 checkIAE(new Runnable() { public void run() { dec.decode(srcStr); }});
422
423 // decode(ByteBuffer)
424 checkIAE(new Runnable() { public void run() { dec.decode(srcBB); }});
425
426 // wrap stream
427 checkIOE(new Testable() {
428 public void test() throws IOException {
429 try (InputStream is = dec.wrap(new ByteArrayInputStream(srcBytes))) {
430 while (is.read() != -1);
431 }
432 }});
433 }
434 }
435 }
436
437 private static void testDecodeUnpadded() throws Throwable {
438 byte[] srcA = new byte[] { 'Q', 'Q' };
439 byte[] srcAA = new byte[] { 'Q', 'Q', 'E'};
440 Base64.Decoder dec = Base64.getDecoder();
441 byte[] ret = dec.decode(srcA);
442 if (ret[0] != 'A')
443 throw new RuntimeException("Decoding unpadding input A failed");
444 ret = dec.decode(srcAA);
445 if (ret[0] != 'A' && ret[1] != 'A')
446 throw new RuntimeException("Decoding unpadding input AA failed");
447 ret = new byte[10];
448 if (dec.wrap(new ByteArrayInputStream(srcA)).read(ret) != 1 &&
449 ret[0] != 'A')
450 throw new RuntimeException("Decoding unpadding input A from stream failed");
451 if (dec.wrap(new ByteArrayInputStream(srcA)).read(ret) != 2 &&
452 ret[0] != 'A' && ret[1] != 'A')
453 throw new RuntimeException("Decoding unpadding input AA from stream failed");
454 }
455
456 // single-non-base64-char should be ignored for mime decoding, but
457 // iae for basic decoding
458 private static void testSingleNonBase64MimeDec() throws Throwable {
459 for (String nonBase64 : new String[] {"#", "(", "!", "\\", "-", "_"}) {
460 if (Base64.getMimeDecoder().decode(nonBase64).length != 0) {
461 throw new RuntimeException("non-base64 char is not ignored");
462 }
463 try {
464 Base64.getDecoder().decode(nonBase64);
465 throw new RuntimeException("No IAE for single non-base64 char");
466 } catch (IllegalArgumentException iae) {}
467 }
468 }
469
470 private static final void testEncode(Base64.Encoder enc, ByteBuffer bin, byte[] expected)
471 throws Throwable {
472
473 ByteBuffer bout = enc.encode(bin);
474 byte[] buf = new byte[bout.remaining()];
475 bout.get(buf);
476 if (bin.hasRemaining()) {
477 throw new RuntimeException(
478 "Base64 enc.encode(ByteBuffer) failed!");
479 }
480 checkEqual(buf, expected, "Base64 enc.encode(bf, bf) failed!");
481 }
482
483 private static final void testDecode(Base64.Decoder dec, ByteBuffer bin, byte[] expected)
484 throws Throwable {
485
486 ByteBuffer bout = dec.decode(bin);
487 byte[] buf = new byte[bout.remaining()];
488 bout.get(buf);
489 checkEqual(buf, expected, "Base64 dec.decode(bf) failed!");
490 }
491
492 private static final void checkEqual(int v1, int v2, String msg)
493 throws Throwable {
494 if (v1 != v2) {
495 System.out.printf(" v1=%d%n", v1);
496 System.out.printf(" v2=%d%n", v2);
497 throw new RuntimeException(msg);
498 }
499 }
500
501 private static final void checkEqual(byte[] r1, byte[] r2, String msg)
502 throws Throwable {
503 if (!Arrays.equals(r1, r2)) {
504 System.out.printf(" r1[%d]=[%s]%n", r1.length, new String(r1));
505 System.out.printf(" r2[%d]=[%s]%n", r2.length, new String(r2));
506 throw new RuntimeException(msg);
507 }
508 }
509
510 // remove line feeds,
511 private static final byte[] normalize(byte[] src) {
|