1 package org.catacomb.util;
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 public class Base64 {
31
32 final static String encodingChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
33
34
35
36
37
38
39 public static String encode(String source) {
40 char[] sourceBytes = getPaddedBytes(source);
41 int numGroups = (sourceBytes.length + 2) / 3;
42 char[] targetBytes = new char[4];
43 char[] target = new char[ 4 * numGroups ];
44
45 for (int group = 0; group < numGroups; group++) {
46 convert3To4(sourceBytes, group*3, targetBytes);
47 for (int i = 0; i < targetBytes.length; i++) {
48 target[ i + 4*group ] = encodingChar.charAt(targetBytes[i]);
49 }
50 }
51
52 int numPadBytes = sourceBytes.length - source.length();
53
54 for (int i = target.length-numPadBytes; i < target.length; i++) target[i] = '=';
55 return new String(target);
56 }
57
58
59 private static char[] getPaddedBytes(String source) {
60 char[] converted = source.toCharArray();
61 int requiredLength = 3 * ((converted.length+2) /3);
62 char[] result = new char[ requiredLength ];
63 System.arraycopy(converted, 0, result, 0, converted.length);
64 return result;
65 }
66
67
68 private static void convert3To4(char[] source, int sourceIndex, char[] target) {
69 target[0] = (char)(source[ sourceIndex ] >>> 2);
70 target[1] = (char)(((source[ sourceIndex ] & 0x03) << 4) | (source[ sourceIndex+1 ] >>> 4));
71 target[2] = (char)(((source[ sourceIndex+1 ] & 0x0f) << 2) | (source[ sourceIndex+2 ] >>> 6));
72 target[3] = (char)(source[ sourceIndex+2 ] & 0x3f);
73 }
74
75
76
77
78
79
80 public static String decode(String source) {
81 if (source.length()%4 != 0) throw new RuntimeException("valid Base64 codes have a multiple of 4 characters");
82 int numGroups = source.length() / 4;
83 int numExtraBytes = source.endsWith("==") ? 2 : (source.endsWith("=") ? 1 : 0);
84 byte[] targetBytes = new byte[ 3*numGroups ];
85 byte[] sourceBytes = new byte[4];
86 for (int group = 0; group < numGroups; group++) {
87 for (int i = 0; i < sourceBytes.length; i++) {
88 sourceBytes[i] = (byte) Math.max(0, encodingChar.indexOf(source.charAt(4*group+i)));
89 }
90 convert4To3(sourceBytes, targetBytes, group*3);
91 }
92 return new String(targetBytes, 0, targetBytes.length - numExtraBytes);
93 }
94
95
96 private static void convert4To3(byte[] source, byte[] target, int targetIndex) {
97 target[ targetIndex ] = (byte)((source[0] << 2) | (source[1] >>> 4));
98 target[ targetIndex+1 ] = (byte)(((source[1] & 0x0f) << 4) | (source[2] >>> 2));
99 target[ targetIndex+2 ] = (byte)(((source[2] & 0x03) << 6) | (source[3]));
100 }
101
102 }