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