1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.codec.binary;
19
20 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertFalse;
23 import static org.junit.jupiter.api.Assertions.assertNotNull;
24 import static org.junit.jupiter.api.Assertions.assertThrows;
25 import static org.junit.jupiter.api.Assertions.assertTrue;
26
27 import java.io.BufferedReader;
28 import java.io.ByteArrayInputStream;
29 import java.io.ByteArrayOutputStream;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.InputStreamReader;
33
34 import org.apache.commons.codec.CodecPolicy;
35 import org.junit.jupiter.api.Test;
36
37
38
39
40 class Base64InputStreamTest {
41
42
43
44
45 private static final String ENCODED_B64 = "AAAA////";
46
47 private static final byte[] CRLF = { (byte) '\r', (byte) '\n' };
48
49 private static final byte[] LF = { (byte) '\n' };
50
51 private static final String STRING_FIXTURE = "Hello World";
52
53
54
55
56
57
58
59 @Test
60 void testAvailable() throws Throwable {
61 final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
62 try (Base64InputStream b64stream = new Base64InputStream(ins)) {
63 assertEquals(1, b64stream.available());
64 assertEquals(6, b64stream.skip(10));
65
66 assertEquals(0, b64stream.available());
67 assertEquals(-1, b64stream.read());
68 assertEquals(-1, b64stream.read());
69 assertEquals(0, b64stream.available());
70 }
71 }
72
73 private void testBase64EmptyInputStream(final int chuckSize) throws Exception {
74 final byte[] emptyEncoded = {};
75 final byte[] emptyDecoded = {};
76 testByteByByte(emptyEncoded, emptyDecoded, chuckSize, CRLF);
77 testByChunk(emptyEncoded, emptyDecoded, chuckSize, CRLF);
78 }
79
80
81
82
83
84
85
86 @Test
87 void testBase64EmptyInputStreamMimeChuckSize() throws Exception {
88 testBase64EmptyInputStream(BaseNCodec.MIME_CHUNK_SIZE);
89 }
90
91
92
93
94
95
96
97 @Test
98 void testBase64EmptyInputStreamPemChuckSize() throws Exception {
99 testBase64EmptyInputStream(BaseNCodec.PEM_CHUNK_SIZE);
100 }
101
102
103
104
105
106
107
108 @Test
109 void testBase64InputStreamByChunk() throws Exception {
110
111 byte[] encoded = StringUtils.getBytesUtf8("SGVsbG8gV29ybGQ=\r\n");
112 byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
113 testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF);
114
115
116 encoded = StringUtils.getBytesUtf8("AA==\r\n");
117 decoded = new byte[] { (byte) 0 };
118 testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF);
119
120
121 encoded = StringUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE);
122 decoded = BaseNTestData.DECODED;
123 testByChunk(encoded, decoded, BaseNCodec.PEM_CHUNK_SIZE, LF);
124
125
126 final String singleLine = Base64TestData.ENCODED_64_CHARS_PER_LINE.replace("\n", "");
127 encoded = StringUtils.getBytesUtf8(singleLine);
128 decoded = BaseNTestData.DECODED;
129 testByChunk(encoded, decoded, 0, LF);
130
131
132 final BaseNCodec codec = new Base64(0, null, false);
133 for (int i = 0; i <= 150; i++) {
134 final byte[][] randomData = BaseNTestData.randomData(codec, i);
135 encoded = randomData[1];
136 decoded = randomData[0];
137 testByChunk(encoded, decoded, 0, LF);
138 }
139 }
140
141
142
143
144
145
146
147 @Test
148 void testBase64InputStreamByteByByte() throws Exception {
149
150 byte[] encoded = StringUtils.getBytesUtf8("SGVsbG8gV29ybGQ=\r\n");
151 byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
152 testByteByByte(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF);
153
154
155 encoded = StringUtils.getBytesUtf8("AA==\r\n");
156 decoded = new byte[] { (byte) 0 };
157 testByteByByte(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF);
158
159
160 encoded = StringUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE);
161 decoded = BaseNTestData.DECODED;
162 testByteByByte(encoded, decoded, BaseNCodec.PEM_CHUNK_SIZE, LF);
163
164
165 final String singleLine = Base64TestData.ENCODED_64_CHARS_PER_LINE.replace("\n", "");
166 encoded = StringUtils.getBytesUtf8(singleLine);
167 decoded = BaseNTestData.DECODED;
168 testByteByByte(encoded, decoded, 0, LF);
169
170
171 final BaseNCodec codec = new Base64(0, null, false);
172 for (int i = 0; i <= 150; i++) {
173 final byte[][] randomData = BaseNTestData.randomData(codec, i);
174 encoded = randomData[1];
175 decoded = randomData[0];
176 testByteByByte(encoded, decoded, 0, LF);
177 }
178 }
179
180 @Test
181 void testBuilder() {
182 assertNotNull(Base64InputStream.builder().getBaseNCodec());
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203 private void testByChunk(final byte[] encoded, final byte[] decoded, final int chunkSize, final byte[] separator) throws Exception {
204
205 try (InputStream in = new Base64InputStream(new ByteArrayInputStream(decoded), true, chunkSize, separator)) {
206 final byte[] output = BaseNTestData.streamToBytes(in);
207 assertEquals(-1, in.read(), "EOF");
208 assertEquals(-1, in.read(), "Still EOF");
209 assertArrayEquals(encoded, output, "Streaming base64 encode");
210 }
211
212
213 InputStream in = new Base64InputStream(new ByteArrayInputStream(encoded));
214 byte[] output = BaseNTestData.streamToBytes(in);
215
216 assertEquals(-1, in.read(), "EOF");
217 assertEquals(-1, in.read(), "Still EOF");
218 assertArrayEquals(decoded, output, "Streaming base64 decode");
219
220
221 in = new ByteArrayInputStream(decoded);
222 for (int i = 0; i < 10; i++) {
223 in = new Base64InputStream(in, true, chunkSize, separator);
224 in = new Base64InputStream(in, false);
225 }
226 output = BaseNTestData.streamToBytes(in);
227
228 assertEquals(-1, in.read(), "EOF");
229 assertEquals(-1, in.read(), "Still EOF");
230 assertArrayEquals(decoded, output, "Streaming base64 wrap-wrap-wrap!");
231 in.close();
232 }
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252 private void testByteByByte(final byte[] encoded, final byte[] decoded, final int chunkSize, final byte[] separator) throws Exception {
253 byte[] output = new byte[encoded.length];
254
255 try (InputStream in = new Base64InputStream(new ByteArrayInputStream(decoded), true, chunkSize, separator)) {
256 for (int i = 0; i < output.length; i++) {
257 output[i] = (byte) in.read();
258 }
259
260 assertEquals(-1, in.read(), "EOF");
261 assertEquals(-1, in.read(), "Still EOF");
262 assertArrayEquals(encoded, output, "Streaming base64 encode");
263
264 }
265
266 try (InputStream in = new Base64InputStream(new ByteArrayInputStream(encoded))) {
267 output = new byte[decoded.length];
268 for (int i = 0; i < output.length; i++) {
269 output[i] = (byte) in.read();
270 }
271
272 assertEquals(-1, in.read(), "EOF");
273 assertEquals(-1, in.read(), "Still EOF");
274 assertArrayEquals(decoded, output, "Streaming base64 decode");
275 }
276
277
278 InputStream in = new ByteArrayInputStream(decoded);
279 for (int i = 0; i < 10; i++) {
280 in = new Base64InputStream(in, true, chunkSize, separator);
281 in = new Base64InputStream(in, false);
282 }
283 output = new byte[decoded.length];
284 for (int i = 0; i < output.length; i++) {
285 output[i] = (byte) in.read();
286 }
287
288 assertEquals(-1, in.read(), "EOF");
289 assertEquals(-1, in.read(), "Still EOF");
290 assertArrayEquals(decoded, output, "Streaming base64 wrap-wrap-wrap!");
291 }
292
293
294
295
296
297
298
299 @Test
300 void testCodec101() throws Exception {
301 final byte[] codec101 = StringUtils.getBytesUtf8(Base64TestData.CODEC_101_INPUT_LENGTH_IS_MULTIPLE_OF_3);
302 final ByteArrayInputStream bais = new ByteArrayInputStream(codec101);
303 try (Base64InputStream in = new Base64InputStream(bais)) {
304 final byte[] result = new byte[8192];
305 int c = in.read(result);
306 assertTrue(c > 0, "Codec101: First read successful [c=" + c + "]");
307
308 c = in.read(result);
309 assertTrue(c < 0, "Codec101: Second read should report end-of-stream [c=" + c + "]");
310 }
311 }
312
313
314
315
316 @Test
317 void testCodec105() throws IOException {
318 try (Base64InputStream in = new Base64InputStream(new Codec105ErrorInputStream(), true, 0, null)) {
319 for (int i = 0; i < 5; i++) {
320 in.read();
321 }
322 }
323 }
324
325
326
327
328 @Test
329 void testCodec130() throws IOException {
330 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
331 try (Base64OutputStream base64os = new Base64OutputStream(bos)) {
332 base64os.write(StringUtils.getBytesUtf8(STRING_FIXTURE));
333 }
334
335 final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
336 final Base64InputStream ins = new Base64InputStream(bis);
337
338
339 ins.skip(1);
340 final byte[] decodedBytes = BaseNTestData.streamToBytes(ins, new byte[64]);
341 final String str = StringUtils.newStringUtf8(decodedBytes);
342
343 assertEquals(STRING_FIXTURE.substring(1), str);
344 }
345
346
347
348
349
350
351
352 @Test
353 void testCodec98NPE() throws Exception {
354 final byte[] codec98 = StringUtils.getBytesUtf8(Base64TestData.CODEC_98_NPE);
355 final ByteArrayInputStream data = new ByteArrayInputStream(codec98);
356 final Base64InputStream stream = new Base64InputStream(data);
357
358
359 final byte[] decodedBytes = BaseNTestData.streamToBytes(stream, new byte[1024]);
360
361 final String decoded = StringUtils.newStringUtf8(decodedBytes);
362 assertEquals(Base64TestData.CODEC_98_NPE_DECODED, decoded, "codec-98 NPE Base64InputStream");
363 }
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380 @Test
381 void testInputStreamReader() throws Exception {
382 final byte[] codec101 = StringUtils.getBytesUtf8(Base64TestData.CODEC_101_INPUT_LENGTH_IS_MULTIPLE_OF_3);
383 final ByteArrayInputStream bais = new ByteArrayInputStream(codec101);
384 final Base64InputStream in = new Base64InputStream(bais);
385 final InputStreamReader isr = new InputStreamReader(in);
386 try (BufferedReader br = new BufferedReader(isr)) {
387 final String line = br.readLine();
388 assertNotNull(line, "Codec101: InputStreamReader works!");
389 }
390 }
391
392
393
394
395
396
397
398 @Test
399 void testMarkSupported() throws Exception {
400 final byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
401 final ByteArrayInputStream bin = new ByteArrayInputStream(decoded);
402 try (Base64InputStream in = new Base64InputStream(bin, true, 4, new byte[] { 0, 0, 0 })) {
403
404 assertFalse(in.markSupported(), "Base64InputStream.markSupported() is false");
405 }
406 }
407
408
409
410
411
412
413
414 @Test
415 void testRead0() throws Exception {
416 final byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
417 final byte[] buf = new byte[1024];
418 int bytesRead = 0;
419 final ByteArrayInputStream bin = new ByteArrayInputStream(decoded);
420 try (Base64InputStream in = new Base64InputStream(bin, true, 4, new byte[] { 0, 0, 0 })) {
421 bytesRead = in.read(buf, 0, 0);
422 assertEquals(0, bytesRead, "Base64InputStream.read(buf, 0, 0) returns 0");
423 }
424 }
425
426
427
428
429
430
431
432 @Test
433 void testReadMultipleBufferSizes() throws Exception {
434 final byte[][] randomData = BaseNTestData.randomData(new Base64(0, null, false), 1024 * 64);
435 final byte[] encoded = randomData[1];
436 final byte[] decoded = randomData[0];
437 final ByteArrayInputStream bin = new ByteArrayInputStream(encoded);
438 final ByteArrayOutputStream out = new ByteArrayOutputStream();
439 try (Base64InputStream in = new Base64InputStream(bin)) {
440 for (final int i : new int[] { 4 * 1024, 4 * 1024, 8 * 1024, 8 * 1024, 16 * 1024, 16 * 1024, 8 * 1024 }) {
441 final byte[] buf = new byte[i];
442 final int bytesRead = in.read(buf);
443 assertEquals(i, bytesRead);
444 out.write(buf, 0, bytesRead);
445 }
446 }
447 assertArrayEquals(decoded, out.toByteArray());
448 }
449
450
451
452
453
454
455
456 @Test
457 void testReadNull() throws Exception {
458 final byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
459 final ByteArrayInputStream bin = new ByteArrayInputStream(decoded);
460 try (Base64InputStream in = new Base64InputStream(bin, true, 4, new byte[] { 0, 0, 0 })) {
461 assertThrows(NullPointerException.class, () -> in.read(null, 0, 0));
462 }
463 }
464
465
466
467
468
469
470
471 @Test
472 void testReadOutOfBounds() throws Exception {
473 final byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
474 final byte[] buf = new byte[1024];
475 final ByteArrayInputStream bin = new ByteArrayInputStream(decoded);
476 try (Base64InputStream in = new Base64InputStream(bin, true, 4, new byte[] {0, 0, 0})) {
477 assertThrows(IndexOutOfBoundsException.class, () -> in.read(buf, -1, 0), "Base64InputStream.read(buf, -1, 0)");
478 assertThrows(IndexOutOfBoundsException.class, () -> in.read(buf, 0, -1), "Base64InputStream.read(buf, 0, -1)");
479 assertThrows(IndexOutOfBoundsException.class, () -> in.read(buf, buf.length + 1, 0), "Base64InputStream.read(buf, buf.length + 1, 0)");
480 assertThrows(IndexOutOfBoundsException.class, () -> in.read(buf, buf.length - 1, 2), "Base64InputStream.read(buf, buf.length - 1, 2)");
481 }
482 }
483
484
485
486
487
488
489
490 @Test
491 void testSkipBig() throws Throwable {
492 final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
493 try (Base64InputStream b64stream = new Base64InputStream(ins)) {
494 assertEquals(6, b64stream.skip(Integer.MAX_VALUE));
495
496 assertEquals(-1, b64stream.read());
497 assertEquals(-1, b64stream.read());
498 }
499 }
500
501
502
503
504
505
506
507 @Test
508 void testSkipNone() throws Throwable {
509 final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
510 try (Base64InputStream b64stream = new Base64InputStream(ins)) {
511 final byte[] actualBytes = new byte[6];
512 assertEquals(0, b64stream.skip(0));
513 b64stream.read(actualBytes, 0, actualBytes.length);
514 assertArrayEquals(actualBytes, new byte[] { 0, 0, 0, (byte) 255, (byte) 255, (byte) 255 });
515
516 assertEquals(-1, b64stream.read());
517 }
518 }
519
520
521
522
523
524
525
526 @Test
527 void testSkipPastEnd() throws Throwable {
528 final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
529 try (Base64InputStream b64stream = new Base64InputStream(ins)) {
530
531 assertEquals(6, b64stream.skip(10));
532
533 assertEquals(-1, b64stream.read());
534 assertEquals(-1, b64stream.read());
535 }
536 }
537
538
539
540
541
542
543
544 @Test
545 void testSkipToEnd() throws Throwable {
546 final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
547 try (Base64InputStream b64stream = new Base64InputStream(ins)) {
548
549 assertEquals(6, b64stream.skip(6));
550
551 assertEquals(-1, b64stream.read());
552 assertEquals(-1, b64stream.read());
553 }
554 }
555
556
557
558
559
560
561
562 @Test
563 void testSkipWrongArgument() throws Throwable {
564 final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_B64));
565 try (Base64InputStream b64stream = new Base64InputStream(ins)) {
566 assertThrows(IllegalArgumentException.class, () -> b64stream.skip(-10));
567 }
568 }
569
570
571
572
573
574
575
576 @Test
577 void testStrictDecoding() throws Exception {
578 for (final String s : Base64Test.BASE64_IMPOSSIBLE_CASES) {
579 final byte[] encoded = StringUtils.getBytesUtf8(s);
580 final Base64InputStream in = new Base64InputStream(new ByteArrayInputStream(encoded), false);
581
582 assertFalse(in.isStrictDecoding());
583 BaseNTestData.streamToBytes(in);
584
585 final Base64InputStream in2 = new Base64InputStream(new ByteArrayInputStream(encoded), false, 0, null, CodecPolicy.STRICT);
586 assertTrue(in2.isStrictDecoding());
587 assertThrows(IllegalArgumentException.class, () -> BaseNTestData.streamToBytes(in2));
588
589 try (Base64InputStream in3 = Base64InputStream.builder()
590 .setInputStream(new ByteArrayInputStream(encoded))
591 .setEncode(false)
592 .setBaseNCodec(Base64.builder().setLineLength(0).setLineSeparator(null).setDecodingPolicy(CodecPolicy.STRICT).get())
593 .get()) {
594 assertTrue(in3.isStrictDecoding());
595 assertThrows(IllegalArgumentException.class, () -> BaseNTestData.streamToBytes(in3));
596 }
597 }
598 }
599 }