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