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