1
2
3
4
5
6
7 package org.eclipse.jgit.util;
8
9 import java.io.UnsupportedEncodingException;
10 import java.text.MessageFormat;
11 import java.util.Arrays;
12
13 import org.eclipse.jgit.internal.JGitText;
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 public class Base64 {
30
31 private final static byte EQUALS_SIGN = (byte) '=';
32
33
34 private final static byte EQUALS_SIGN_DEC = -1;
35
36
37 private final static byte WHITE_SPACE_DEC = -2;
38
39
40 private final static byte INVALID_DEC = -3;
41
42
43 private final static String UTF_8 = "UTF-8";
44
45
46 private final static byte[] ENC;
47
48
49
50
51
52
53 private final static byte[] DEC;
54
55 static {
56 try {
57 ENC = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
58 + "abcdefghijklmnopqrstuvwxyz"
59 + "0123456789"
60 + "+/"
61 ).getBytes(UTF_8);
62 } catch (UnsupportedEncodingException uee) {
63 throw new RuntimeException(uee.getMessage(), uee);
64 }
65
66 DEC = new byte[128];
67 Arrays.fill(DEC, INVALID_DEC);
68
69 for (int i = 0; i < 64; i++)
70 DEC[ENC[i]] = (byte) i;
71 DEC[EQUALS_SIGN] = EQUALS_SIGN_DEC;
72
73 DEC['\t'] = WHITE_SPACE_DEC;
74 DEC['\n'] = WHITE_SPACE_DEC;
75 DEC['\r'] = WHITE_SPACE_DEC;
76 DEC[' '] = WHITE_SPACE_DEC;
77 }
78
79
80 private Base64() {
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 private static void encode3to4(byte[] source, int srcOffset,
107 int numSigBytes, byte[] destination, int destOffset) {
108
109
110
111 int inBuff = 0;
112 switch (numSigBytes) {
113 case 3:
114 inBuff |= (source[srcOffset + 2] << 24) >>> 24;
115
116
117 case 2:
118 inBuff |= (source[srcOffset + 1] << 24) >>> 16;
119
120
121 case 1:
122 inBuff |= (source[srcOffset] << 24) >>> 8;
123 }
124
125 switch (numSigBytes) {
126 case 3:
127 destination[destOffset] = ENC[(inBuff >>> 18)];
128 destination[destOffset + 1] = ENC[(inBuff >>> 12) & 0x3f];
129 destination[destOffset + 2] = ENC[(inBuff >>> 6) & 0x3f];
130 destination[destOffset + 3] = ENC[(inBuff) & 0x3f];
131 break;
132
133 case 2:
134 destination[destOffset] = ENC[(inBuff >>> 18)];
135 destination[destOffset + 1] = ENC[(inBuff >>> 12) & 0x3f];
136 destination[destOffset + 2] = ENC[(inBuff >>> 6) & 0x3f];
137 destination[destOffset + 3] = EQUALS_SIGN;
138 break;
139
140 case 1:
141 destination[destOffset] = ENC[(inBuff >>> 18)];
142 destination[destOffset + 1] = ENC[(inBuff >>> 12) & 0x3f];
143 destination[destOffset + 2] = EQUALS_SIGN;
144 destination[destOffset + 3] = EQUALS_SIGN;
145 break;
146 }
147 }
148
149
150
151
152
153
154
155
156 public static String encodeBytes(byte[] source) {
157 return encodeBytes(source, 0, source.length);
158 }
159
160
161
162
163
164
165
166
167
168
169
170
171 public static String encodeBytes(byte[] source, int off, int len) {
172 final int len43 = len * 4 / 3;
173
174 byte[] outBuff = new byte[len43 + ((len % 3) > 0 ? 4 : 0)];
175 int d = 0;
176 int e = 0;
177 int len2 = len - 2;
178
179 for (; d < len2; d += 3, e += 4)
180 encode3to4(source, d + off, 3, outBuff, e);
181
182 if (d < len) {
183 encode3to4(source, d + off, len - d, outBuff, e);
184 e += 4;
185 }
186
187 try {
188 return new String(outBuff, 0, e, UTF_8);
189 } catch (UnsupportedEncodingException uue) {
190 return new String(outBuff, 0, e);
191 }
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 private static int decode4to3(byte[] source, int srcOffset,
216 byte[] destination, int destOffset) {
217
218 if (source[srcOffset + 2] == EQUALS_SIGN) {
219 int outBuff = ((DEC[source[srcOffset]] & 0xFF) << 18)
220 | ((DEC[source[srcOffset + 1]] & 0xFF) << 12);
221 destination[destOffset] = (byte) (outBuff >>> 16);
222 return 1;
223 }
224
225
226 else if (source[srcOffset + 3] == EQUALS_SIGN) {
227 int outBuff = ((DEC[source[srcOffset]] & 0xFF) << 18)
228 | ((DEC[source[srcOffset + 1]] & 0xFF) << 12)
229 | ((DEC[source[srcOffset + 2]] & 0xFF) << 6);
230 destination[destOffset] = (byte) (outBuff >>> 16);
231 destination[destOffset + 1] = (byte) (outBuff >>> 8);
232 return 2;
233 }
234
235
236 else {
237 int outBuff = ((DEC[source[srcOffset]] & 0xFF) << 18)
238 | ((DEC[source[srcOffset + 1]] & 0xFF) << 12)
239 | ((DEC[source[srcOffset + 2]] & 0xFF) << 6)
240 | ((DEC[source[srcOffset + 3]] & 0xFF));
241
242 destination[destOffset] = (byte) (outBuff >> 16);
243 destination[destOffset + 1] = (byte) (outBuff >> 8);
244 destination[destOffset + 2] = (byte) (outBuff);
245
246 return 3;
247 }
248 }
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263 public static byte[] decode(byte[] source, int off, int len) {
264 byte[] outBuff = new byte[len * 3 / 4];
265 int outBuffPosn = 0;
266
267 byte[] b4 = new byte[4];
268 int b4Posn = 0;
269
270 for (int i = off; i < off + len; i++) {
271 byte sbiCrop = (byte) (source[i] & 0x7f);
272 byte sbiDecode = DEC[sbiCrop];
273
274 if (EQUALS_SIGN_DEC <= sbiDecode) {
275 b4[b4Posn++] = sbiCrop;
276 if (b4Posn > 3) {
277 outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn);
278 b4Posn = 0;
279
280
281 if (sbiCrop == EQUALS_SIGN)
282 break;
283 }
284
285 } else if (sbiDecode != WHITE_SPACE_DEC)
286 throw new IllegalArgumentException(MessageFormat.format(
287 JGitText.get().badBase64InputCharacterAt,
288 Integer.valueOf(i), Integer.valueOf(source[i] & 0xff)));
289 }
290
291 if (outBuff.length == outBuffPosn)
292 return outBuff;
293
294 byte[] out = new byte[outBuffPosn];
295 System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
296 return out;
297 }
298
299
300
301
302
303
304
305
306 public static byte[] decode(String s) {
307 byte[] bytes;
308 try {
309 bytes = s.getBytes(UTF_8);
310 } catch (UnsupportedEncodingException uee) {
311 bytes = s.getBytes();
312 }
313 return decode(bytes, 0, bytes.length);
314 }
315 }