1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 package org.mule.util;
62
63 import java.io.BufferedInputStream;
64 import java.io.ByteArrayInputStream;
65 import java.io.File;
66 import java.io.FileInputStream;
67 import java.io.FileOutputStream;
68 import java.io.FilterInputStream;
69 import java.io.FilterOutputStream;
70 import java.io.IOException;
71 import java.io.ObjectInputStream;
72 import java.io.ObjectOutputStream;
73 import java.io.Serializable;
74 import java.io.UnsupportedEncodingException;
75 import java.util.zip.GZIPInputStream;
76 import java.util.zip.GZIPOutputStream;
77
78 import org.apache.commons.io.IOUtils;
79 import org.apache.commons.io.output.ByteArrayOutputStream;
80
81 public final class Base64
82 {
83
84
85
86
87 public static final int NO_OPTIONS = 0;
88
89
90 public static final int ENCODE = 1;
91
92
93 public static final int DECODE = 0;
94
95
96 public static final int GZIP = 2;
97
98
99 public static final int DONT_BREAK_LINES = 8;
100
101
102 public static final String PREFERRED_ENCODING = "UTF-8";
103
104
105
106
107 private static final int MAX_LINE_LENGTH = 76;
108
109
110 private static final byte EQUALS_SIGN = (byte) '=';
111
112
113 private static final byte NEW_LINE = (byte) '\n';
114
115
116 private static final byte[] ALPHABET;
117
118 private static final byte[] NATIVE_ALPHABET =
119
120 {
121 (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I',
122 (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R',
123 (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', (byte) 'a',
124 (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j',
125 (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's',
126 (byte) 't', (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1',
127 (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+',
128 (byte) '/'
129 };
130
131
132 static
133 {
134 byte[] bytes;
135 try
136 {
137 bytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes(PREFERRED_ENCODING);
138 }
139 catch (java.io.UnsupportedEncodingException use)
140 {
141 bytes = NATIVE_ALPHABET;
142 }
143 ALPHABET = bytes;
144 }
145
146
147
148
149
150 private static final byte[] DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9,
151
152
153 -5, -5,
154 -9, -9,
155 -5,
156 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
157 -9, -9, -9, -9, -9,
158 -5,
159 -9, -9, -9, -9, -9, -9, -9, -9, -9, -9,
160 62,
161 -9, -9, -9,
162 63,
163 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
164 -9, -9, -9,
165 -1,
166 -9, -9, -9,
167 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
168 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
169 -9, -9, -9, -9, -9, -9,
170 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
171
172 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
173
174 -9, -9, -9, -9
175
176
177
178
179
180
181
182
183
184
185
186
187 };
188
189
190
191
192 private static final byte WHITE_SPACE_ENC = -5;
193
194 private static final byte EQUALS_SIGN_ENC = -1;
195
196
197
198
199 private Base64()
200 {
201 super();
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 private static byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes)
220 {
221 encode3to4(threeBytes, 0, numSigBytes, b4, 0);
222 return b4;
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243 private static byte[] encode3to4(byte[] source,
244 int srcOffset,
245 int numSigBytes,
246 byte[] destination,
247 int destOffset)
248 {
249
250
251
252
253
254
255
256
257
258
259
260
261 int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0)
262 | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
263 | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
264
265 switch (numSigBytes)
266 {
267 case 3 :
268 destination[destOffset] = ALPHABET[(inBuff >>> 18)];
269 destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
270 destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
271 destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
272 return destination;
273
274 case 2 :
275 destination[destOffset] = ALPHABET[(inBuff >>> 18)];
276 destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
277 destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
278 destination[destOffset + 3] = EQUALS_SIGN;
279 return destination;
280
281 case 1 :
282 destination[destOffset] = ALPHABET[(inBuff >>> 18)];
283 destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
284 destination[destOffset + 2] = EQUALS_SIGN;
285 destination[destOffset + 3] = EQUALS_SIGN;
286 return destination;
287
288 default :
289 return destination;
290 }
291 }
292
293
294
295
296
297
298
299
300
301
302
303 public static String encodeObject(Serializable serializableObject) throws IOException
304 {
305 return encodeObject(serializableObject, NO_OPTIONS);
306 }
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334 public static String encodeObject(Serializable serializableObject, int options) throws IOException
335 {
336
337 ByteArrayOutputStream baos = null;
338 OutputStream b64os = null;
339 ObjectOutputStream oos = null;
340 GZIPOutputStream gzos = null;
341
342
343 int gzip = (options & GZIP);
344 int dontBreakLines = (options & DONT_BREAK_LINES);
345
346 try
347 {
348
349 baos = new ByteArrayOutputStream(4096);
350 b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines);
351
352
353 if (gzip == GZIP)
354 {
355 gzos = new GZIPOutputStream(b64os);
356 oos = new ObjectOutputStream(gzos);
357 }
358 else
359 {
360 oos = new ObjectOutputStream(b64os);
361 }
362
363 oos.writeObject(serializableObject);
364
365 if (gzos != null)
366 {
367 gzos.finish();
368 gzos.close();
369 }
370
371 oos.close();
372 }
373 catch (IOException e)
374 {
375 return null;
376 }
377 finally
378 {
379 IOUtils.closeQuietly(oos);
380 IOUtils.closeQuietly(gzos);
381 IOUtils.closeQuietly(b64os);
382 IOUtils.closeQuietly(baos);
383 }
384
385
386 try
387 {
388 return new String(baos.toByteArray(), PREFERRED_ENCODING);
389 }
390 catch (UnsupportedEncodingException uue)
391 {
392 return new String(baos.toByteArray());
393 }
394
395 }
396
397
398
399
400
401
402
403 public static String encodeBytes(byte[] source) throws IOException
404 {
405 return encodeBytes(source, 0, source.length, NO_OPTIONS);
406 }
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431 public static String encodeBytes(byte[] source, int options) throws IOException
432 {
433 return encodeBytes(source, 0, source.length, options);
434 }
435
436
437
438
439
440
441
442
443
444 public static String encodeBytes(byte[] source, int off, int len) throws IOException
445 {
446 return encodeBytes(source, off, len, NO_OPTIONS);
447 }
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474 public static String encodeBytes(byte[] source, int off, int len, int options) throws IOException
475 {
476
477 int dontBreakLines = (options & DONT_BREAK_LINES);
478 int gzip = (options & GZIP);
479
480
481 if (gzip == GZIP)
482 {
483 ByteArrayOutputStream baos = null;
484 GZIPOutputStream gzos = null;
485 Base64.OutputStream b64os = null;
486
487 try
488 {
489
490 baos = new ByteArrayOutputStream(4096);
491 b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines);
492 gzos = new GZIPOutputStream(b64os);
493
494 gzos.write(source, off, len);
495 gzos.finish();
496 gzos.close();
497 }
498 catch (IOException e)
499 {
500 throw e;
501 }
502 finally
503 {
504 IOUtils.closeQuietly(gzos);
505 IOUtils.closeQuietly(b64os);
506 IOUtils.closeQuietly(baos);
507 }
508
509
510 try
511 {
512 return new String(baos.toByteArray(), PREFERRED_ENCODING);
513 }
514 catch (UnsupportedEncodingException uue)
515 {
516 return new String(baos.toByteArray());
517 }
518 }
519
520
521 else
522 {
523
524 boolean breakLines = dontBreakLines == 0;
525
526 int len43 = len * 4 / 3;
527 byte[] outBuff = new byte[(len43)
528 + ((len % 3) > 0 ? 4 : 0)
529
530 + (breakLines ? (len43 / MAX_LINE_LENGTH) : 0)];
531
532
533 int d = 0;
534 int e = 0;
535 int len2 = len - 2;
536 int lineLength = 0;
537 for (; d < len2; d += 3, e += 4)
538 {
539 encode3to4(source, d + off, 3, outBuff, e);
540
541 lineLength += 4;
542 if (breakLines && lineLength == MAX_LINE_LENGTH)
543 {
544 outBuff[e + 4] = NEW_LINE;
545 e++;
546 lineLength = 0;
547 }
548 }
549
550 if (d < len)
551 {
552 encode3to4(source, d + off, len - d, outBuff, e);
553 e += 4;
554 }
555
556
557 try
558 {
559 return new String(outBuff, 0, e, PREFERRED_ENCODING);
560 }
561 catch (UnsupportedEncodingException uue)
562 {
563 return new String(outBuff, 0, e);
564 }
565
566 }
567
568 }
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589 private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset)
590 {
591
592 if (source[srcOffset + 2] == EQUALS_SIGN)
593 {
594
595
596
597
598 int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
599 | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);
600
601 destination[destOffset] = (byte) (outBuff >>> 16);
602 return 1;
603 }
604
605
606 else if (source[srcOffset + 3] == EQUALS_SIGN)
607 {
608
609
610
611
612
613 int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
614 | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
615 | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6);
616
617 destination[destOffset] = (byte) (outBuff >>> 16);
618 destination[destOffset + 1] = (byte) (outBuff >>> 8);
619 return 2;
620 }
621
622
623 else
624 {
625 try
626 {
627
628
629
630
631
632
633
634 int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
635 | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
636 | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6)
637 | ((DECODABET[source[srcOffset + 3]] & 0xFF));
638
639 destination[destOffset] = (byte) (outBuff >> 16);
640 destination[destOffset + 1] = (byte) (outBuff >> 8);
641 destination[destOffset + 2] = (byte) (outBuff);
642
643 return 3;
644 }
645 catch (Exception e)
646 {
647
648 StringBuffer msg = new StringBuffer(64);
649 msg.append(source[srcOffset]).append(": ").append(DECODABET[source[srcOffset]]);
650 msg.append(source[srcOffset + 1]).append(": ").append(DECODABET[source[srcOffset + 1]]);
651 msg.append(source[srcOffset + 2]).append(": ").append(DECODABET[source[srcOffset + 2]]);
652 msg.append(source[srcOffset + 3]).append(": ").append(DECODABET[source[srcOffset + 3]]);
653 throw (IllegalStateException) new IllegalStateException(msg.toString()).initCause(e);
654 }
655 }
656 }
657
658
659
660
661
662
663
664
665
666
667
668
669 public static byte[] decode(byte[] source, int off, int len)
670 {
671 int len34 = len * 3 / 4;
672 byte[] outBuff = new byte[len34];
673 int outBuffPosn = 0;
674
675 byte[] b4 = new byte[4];
676 int b4Posn = 0;
677 int i = 0;
678 byte sbiCrop = 0;
679 byte sbiDecode = 0;
680 for (i = off; i < off + len; i++)
681 {
682 sbiCrop = (byte) (source[i] & 0x7f);
683 sbiDecode = DECODABET[sbiCrop];
684
685 if (sbiDecode >= WHITE_SPACE_ENC)
686
687 {
688 if (sbiDecode >= EQUALS_SIGN_ENC)
689 {
690 b4[b4Posn++] = sbiCrop;
691 if (b4Posn > 3)
692 {
693 outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn);
694 b4Posn = 0;
695
696
697 if (sbiCrop == EQUALS_SIGN)
698 {
699 break;
700 }
701 }
702
703 }
704
705 }
706 else
707 {
708 throw new IllegalArgumentException("Bad Base64 input character at " + i + ": " + source[i]
709 + "(decimal)");
710 }
711 }
712
713 byte[] out = new byte[outBuffPosn];
714 System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
715 return out;
716 }
717
718
719
720
721
722
723
724
725
726 public static byte[] decode(String s)
727 {
728 byte[] bytes;
729 try
730 {
731 bytes = s.getBytes(PREFERRED_ENCODING);
732 }
733 catch (UnsupportedEncodingException uee)
734 {
735 bytes = s.getBytes();
736 }
737
738
739
740 bytes = decode(bytes, 0, bytes.length);
741
742
743
744 if (bytes != null && bytes.length >= 4)
745 {
746
747 int head = (bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
748 if (GZIPInputStream.GZIP_MAGIC == head)
749 {
750 ByteArrayInputStream bais = null;
751 GZIPInputStream gzis = null;
752 ByteArrayOutputStream baos = null;
753 byte[] buffer = new byte[4096];
754 int length = 0;
755
756 try
757 {
758 baos = new ByteArrayOutputStream(4096);
759 bais = new ByteArrayInputStream(bytes);
760 gzis = new GZIPInputStream(bais);
761
762 while ((length = gzis.read(buffer)) >= 0)
763 {
764 baos.write(buffer, 0, length);
765 }
766
767
768 bytes = baos.toByteArray();
769
770 }
771 catch (IOException e)
772 {
773
774 }
775 finally
776 {
777 IOUtils.closeQuietly(baos);
778 IOUtils.closeQuietly(gzis);
779 IOUtils.closeQuietly(bais);
780 }
781
782 }
783 }
784
785 return bytes;
786 }
787
788
789
790
791
792
793
794
795
796 public static Object decodeToObject(String encodedObject) throws IOException, ClassNotFoundException
797 {
798
799 byte[] objBytes = decode(encodedObject);
800
801 ByteArrayInputStream bais = null;
802 ObjectInputStream ois = null;
803 Object obj = null;
804
805 try
806 {
807 bais = new ByteArrayInputStream(objBytes);
808 ois = new ObjectInputStream(bais);
809 obj = ois.readObject();
810 }
811 catch (IOException e)
812 {
813 throw e;
814 }
815 catch (java.lang.ClassNotFoundException e)
816 {
817 throw e;
818 }
819 finally
820 {
821 IOUtils.closeQuietly(bais);
822 IOUtils.closeQuietly(ois);
823 }
824
825 return obj;
826 }
827
828
829
830
831
832
833
834
835 public static void encodeToFile(byte[] dataToEncode, String filename) throws IOException
836 {
837 Base64.OutputStream bos = null;
838
839 try
840 {
841 bos = new Base64.OutputStream(new FileOutputStream(filename), Base64.ENCODE);
842 bos.write(dataToEncode);
843 }
844 catch (IOException e)
845 {
846 throw e;
847 }
848 finally
849 {
850 IOUtils.closeQuietly(bos);
851 }
852 }
853
854
855
856
857
858
859
860
861 public static void decodeToFile(String dataToDecode, String filename) throws IOException
862 {
863 Base64.OutputStream bos = null;
864
865 try
866 {
867 bos = new Base64.OutputStream(new FileOutputStream(filename), Base64.DECODE);
868 bos.write(dataToDecode.getBytes(PREFERRED_ENCODING));
869 }
870 catch (IOException e)
871 {
872 throw e;
873 }
874 finally
875 {
876 IOUtils.closeQuietly(bos);
877 }
878 }
879
880
881
882
883
884
885
886
887 public static byte[] decodeFromFile(String filename) throws IOException
888 {
889 byte[] decodedData = null;
890 Base64.InputStream bis = null;
891
892 try
893 {
894
895 File file = FileUtils.newFile(filename);
896 byte[] buffer = null;
897 int length = 0;
898 int numBytes = 0;
899
900
901 if (file.length() > Integer.MAX_VALUE)
902 {
903 throw new IllegalArgumentException("File is too big for this convenience method ("
904 + file.length() + " bytes).");
905 }
906 buffer = new byte[(int) file.length()];
907
908
909 bis = new Base64.InputStream(new BufferedInputStream(new FileInputStream(file)), Base64.DECODE);
910
911
912 while ((numBytes = bis.read(buffer, length, 4096)) >= 0)
913 {
914 length += numBytes;
915 }
916
917
918 decodedData = new byte[length];
919 System.arraycopy(buffer, 0, decodedData, 0, length);
920 }
921 catch (IOException e)
922 {
923 throw e;
924 }
925 finally
926 {
927 IOUtils.closeQuietly(bis);
928 }
929
930 return decodedData;
931 }
932
933
934
935
936
937
938
939
940 public static String encodeFromFile(String filename) throws IOException
941 {
942 String encodedData = null;
943 Base64.InputStream bis = null;
944
945 try
946 {
947
948 File file = FileUtils.newFile(filename);
949 byte[] buffer = new byte[(int) (file.length() * 1.4)];
950 int length = 0;
951 int numBytes = 0;
952
953
954 bis = new Base64.InputStream(new BufferedInputStream(new FileInputStream(file)), Base64.ENCODE);
955
956
957 while ((numBytes = bis.read(buffer, length, 4096)) >= 0)
958 {
959 length += numBytes;
960 }
961
962
963 encodedData = new String(buffer, 0, length, Base64.PREFERRED_ENCODING);
964 }
965 catch (IOException e)
966 {
967 throw e;
968 }
969 finally
970 {
971 IOUtils.closeQuietly(bis);
972 }
973
974 return encodedData;
975 }
976
977
978
979
980
981
982
983
984
985
986
987 public static class InputStream extends FilterInputStream
988 {
989 private boolean encode;
990 private int position;
991 private byte[] buffer;
992 private int bufferLength;
993 private int numSigBytes;
994 private int lineLength;
995 private boolean breakLines;
996
997
998
999
1000
1001
1002
1003 public InputStream(java.io.InputStream in)
1004 {
1005 this(in, DECODE);
1006 }
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030 public InputStream(java.io.InputStream in, int options)
1031 {
1032 super(in);
1033 this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
1034 this.encode = (options & ENCODE) == ENCODE;
1035 this.bufferLength = encode ? 4 : 3;
1036 this.buffer = new byte[bufferLength];
1037 this.position = -1;
1038 this.lineLength = 0;
1039 }
1040
1041
1042
1043
1044
1045
1046
1047
1048 public int read() throws IOException
1049 {
1050
1051 if (position < 0)
1052 {
1053 if (encode)
1054 {
1055 byte[] b3 = new byte[3];
1056 int numBinaryBytes = 0;
1057 for (int i = 0; i < 3; i++)
1058 {
1059 try
1060 {
1061 int b = in.read();
1062
1063
1064 if (b >= 0)
1065 {
1066 b3[i] = (byte) b;
1067 numBinaryBytes++;
1068 }
1069
1070 }
1071 catch (IOException e)
1072 {
1073
1074 if (i == 0)
1075 {
1076 throw e;
1077 }
1078
1079 }
1080 }
1081
1082 if (numBinaryBytes > 0)
1083 {
1084 encode3to4(b3, 0, numBinaryBytes, buffer, 0);
1085 position = 0;
1086 numSigBytes = 4;
1087 }
1088 else
1089 {
1090 return -1;
1091 }
1092 }
1093
1094
1095 else
1096 {
1097 byte[] b4 = new byte[4];
1098 int i = 0;
1099 for (i = 0; i < 4; i++)
1100 {
1101
1102 int b = 0;
1103 do
1104 {
1105 b = in.read();
1106 }
1107 while (b >= 0 && DECODABET[b & 0x7f] <= WHITE_SPACE_ENC);
1108
1109 if (b < 0)
1110 {
1111 break;
1112 }
1113
1114 b4[i] = (byte) b;
1115 }
1116
1117 if (i == 4)
1118 {
1119 numSigBytes = decode4to3(b4, 0, buffer, 0);
1120 position = 0;
1121 }
1122 else if (i == 0)
1123 {
1124 return -1;
1125 }
1126 else
1127 {
1128
1129 throw new IOException("Improperly padded Base64 input.");
1130 }
1131
1132 }
1133 }
1134
1135
1136 if (position >= 0)
1137 {
1138
1139 if (
1140 {
1141 return -1;
1142 }
1143
1144 if (encode && breakLines && lineLength >= MAX_LINE_LENGTH)
1145 {
1146 lineLength = 0;
1147 return '\n';
1148 }
1149 else
1150 {
1151 lineLength++;
1152
1153
1154
1155 int b = buffer[position++];
1156
1157 if (position >= bufferLength)
1158 {
1159 position = -1;
1160 }
1161
1162 return b & 0xFF;
1163
1164 }
1165 }
1166
1167
1168 else
1169 {
1170
1171 throw new IOException("Error in Base64 code reading stream.");
1172 }
1173 }
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186 public int read(byte[] dest, int off, int len) throws IOException
1187 {
1188 int i;
1189 int b;
1190 for (i = 0; i < len; i++)
1191 {
1192 b = read();
1193
1194
1195
1196
1197 if (b >= 0)
1198 {
1199 dest[off + i] = (byte) b;
1200 }
1201 else if (i == 0)
1202 {
1203 return -1;
1204 }
1205 else
1206 {
1207 break;
1208 }
1209 }
1210 return i;
1211 }
1212
1213 }
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225 public static class OutputStream extends FilterOutputStream
1226 {
1227 private boolean encode;
1228 private int position;
1229 private byte[] buffer;
1230 private int bufferLength;
1231 private int lineLength;
1232 private boolean breakLines;
1233 private byte[] b4;
1234 private boolean suspendEncoding;
1235
1236
1237
1238
1239
1240
1241
1242 public OutputStream(java.io.OutputStream out)
1243 {
1244 this(out, ENCODE);
1245 }
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269 public OutputStream(java.io.OutputStream out, int options)
1270 {
1271 super(out);
1272 this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
1273 this.encode = (options & ENCODE) == ENCODE;
1274 this.bufferLength = encode ? 3 : 4;
1275 this.buffer = new byte[bufferLength];
1276 this.position = 0;
1277 this.lineLength = 0;
1278 this.suspendEncoding = false;
1279 this.b4 = new byte[4];
1280 }
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291 public void write(int theByte) throws IOException
1292 {
1293
1294 if (suspendEncoding)
1295 {
1296 super.out.write(theByte);
1297 return;
1298 }
1299
1300
1301 if (encode)
1302 {
1303 buffer[position++] = (byte) theByte;
1304 if (position >= bufferLength)
1305 {
1306 out.write(encode3to4(b4, buffer, bufferLength));
1307
1308 lineLength += 4;
1309 if (breakLines && lineLength >= MAX_LINE_LENGTH)
1310 {
1311 out.write(NEW_LINE);
1312 lineLength = 0;
1313 }
1314
1315 position = 0;
1316 }
1317 }
1318
1319
1320 else
1321 {
1322
1323 if (DECODABET[theByte & 0x7f] > WHITE_SPACE_ENC)
1324 {
1325 buffer[position++] = (byte) theByte;
1326 if (position >= bufferLength)
1327 {
1328 int len = Base64.decode4to3(buffer, 0, b4, 0);
1329 out.write(b4, 0, len);
1330
1331 position = 0;
1332 }
1333 }
1334 else if (DECODABET[theByte & 0x7f] != WHITE_SPACE_ENC)
1335 {
1336 throw new IOException("Invalid character in Base64 data.");
1337 }
1338 }
1339 }
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350 public void write(byte[] theBytes, int off, int len) throws IOException
1351 {
1352
1353 if (suspendEncoding)
1354 {
1355 super.out.write(theBytes, off, len);
1356 return;
1357 }
1358
1359 for (int i = 0; i < len; i++)
1360 {
1361 write(theBytes[off + i]);
1362 }
1363
1364 }
1365
1366
1367
1368
1369
1370 public void flushBase64() throws IOException
1371 {
1372 if (position > 0)
1373 {
1374 if (encode)
1375 {
1376 out.write(encode3to4(b4, buffer, position));
1377 position = 0;
1378 }
1379 else
1380 {
1381 throw new IOException("Base64 input not properly padded.");
1382 }
1383 }
1384
1385 }
1386
1387
1388
1389
1390
1391
1392 public void close() throws IOException
1393 {
1394
1395 flushBase64();
1396
1397
1398
1399 super.close();
1400
1401 buffer = null;
1402 out = null;
1403 }
1404
1405
1406
1407
1408
1409
1410
1411 public void suspendEncoding() throws IOException
1412 {
1413 flushBase64();
1414 this.suspendEncoding = true;
1415 }
1416
1417
1418
1419
1420
1421
1422
1423 public void resumeEncoding()
1424 {
1425 this.suspendEncoding = false;
1426 }
1427
1428 }
1429
1430 }