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