1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.util;
21
22 import java.security.InvalidParameterException;
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 public class Base64 {
42
43
44
45
46
47
48
49
50
51 static final int CHUNK_SIZE = 76;
52
53
54
55
56
57
58 static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes();
59
60
61
62
63 static final int BASELENGTH = 255;
64
65
66
67
68 static final int LOOKUPLENGTH = 64;
69
70
71
72
73 static final int EIGHTBIT = 8;
74
75
76
77
78 static final int SIXTEENBIT = 16;
79
80
81
82
83 static final int TWENTYFOURBITGROUP = 24;
84
85
86
87
88 static final int FOURBYTE = 4;
89
90
91
92
93 static final int SIGN = -128;
94
95
96
97
98 static final byte PAD = (byte) '=';
99
100
101
102 private static byte[] base64Alphabet = new byte[BASELENGTH];
103
104 private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
105
106
107 static {
108 for (int i = 0; i < BASELENGTH; i++) {
109 base64Alphabet[i] = (byte) -1;
110 }
111 for (int i = 'Z'; i >= 'A'; i--) {
112 base64Alphabet[i] = (byte) (i - 'A');
113 }
114 for (int i = 'z'; i >= 'a'; i--) {
115 base64Alphabet[i] = (byte) (i - 'a' + 26);
116 }
117 for (int i = '9'; i >= '0'; i--) {
118 base64Alphabet[i] = (byte) (i - '0' + 52);
119 }
120
121 base64Alphabet['+'] = 62;
122 base64Alphabet['/'] = 63;
123
124 for (int i = 0; i <= 25; i++) {
125 lookUpBase64Alphabet[i] = (byte) ('A' + i);
126 }
127
128 for (int i = 26, j = 0; i <= 51; i++, j++) {
129 lookUpBase64Alphabet[i] = (byte) ('a' + j);
130 }
131
132 for (int i = 52, j = 0; i <= 61; i++, j++) {
133 lookUpBase64Alphabet[i] = (byte) ('0' + j);
134 }
135
136 lookUpBase64Alphabet[62] = (byte) '+';
137 lookUpBase64Alphabet[63] = (byte) '/';
138 }
139
140 private static boolean isBase64(byte octect) {
141 if (octect == PAD) {
142 return true;
143 } else if (base64Alphabet[octect] == -1) {
144 return false;
145 } else {
146 return true;
147 }
148 }
149
150
151
152
153
154
155
156
157
158 public static boolean isArrayByteBase64(byte[] arrayOctect) {
159
160 arrayOctect = discardWhitespace(arrayOctect);
161
162 int length = arrayOctect.length;
163 if (length == 0) {
164
165 return true;
166 }
167 for (int i = 0; i < length; i++) {
168 if (!isBase64(arrayOctect[i])) {
169 return false;
170 }
171 }
172 return true;
173 }
174
175
176
177
178
179
180
181
182 public static byte[] encodeBase64(byte[] binaryData) {
183 return encodeBase64(binaryData, false);
184 }
185
186
187
188
189
190
191
192
193 public static byte[] encodeBase64Chunked(byte[] binaryData) {
194 return encodeBase64(binaryData, true);
195 }
196
197
198
199
200
201
202
203
204
205
206
207
208
209 public Object decode(Object pObject) {
210 if (!(pObject instanceof byte[])) {
211 throw new InvalidParameterException("Parameter supplied to Base64 decode is not a byte[]");
212 }
213 return decode((byte[]) pObject);
214 }
215
216
217
218
219
220
221
222
223 public byte[] decode(byte[] pArray) {
224 return decodeBase64(pArray);
225 }
226
227
228
229
230
231
232
233
234
235
236 public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {
237 int lengthDataBits = binaryData.length * EIGHTBIT;
238 int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
239 int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
240 byte encodedData[] = null;
241 int encodedDataLength = 0;
242 int nbrChunks = 0;
243
244 if (fewerThan24bits != 0) {
245
246 encodedDataLength = (numberTriplets + 1) * 4;
247 } else {
248
249 encodedDataLength = numberTriplets * 4;
250 }
251
252
253
254
255 if (isChunked) {
256
257 nbrChunks = (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math.ceil((float) encodedDataLength / CHUNK_SIZE));
258 encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
259 }
260
261 encodedData = new byte[encodedDataLength];
262
263 byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
264
265 int encodedIndex = 0;
266 int dataIndex = 0;
267 int i = 0;
268 int nextSeparatorIndex = CHUNK_SIZE;
269 int chunksSoFar = 0;
270
271 for (i = 0; i < numberTriplets; i++) {
272 dataIndex = i * 3;
273 b1 = binaryData[dataIndex];
274 b2 = binaryData[dataIndex + 1];
275 b3 = binaryData[dataIndex + 2];
276
277 l = (byte) (b2 & 0x0f);
278 k = (byte) (b1 & 0x03);
279
280 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
281 byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
282 byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
283
284 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
285 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | (k << 4)];
286 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[(l << 2) | val3];
287 encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
288
289 encodedIndex += 4;
290
291
292 if (isChunked) {
293
294 if (encodedIndex == nextSeparatorIndex) {
295 System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedIndex, CHUNK_SEPARATOR.length);
296 chunksSoFar++;
297 nextSeparatorIndex = (CHUNK_SIZE * (chunksSoFar + 1)) + (chunksSoFar * CHUNK_SEPARATOR.length);
298 encodedIndex += CHUNK_SEPARATOR.length;
299 }
300 }
301 }
302
303
304 dataIndex = i * 3;
305
306 if (fewerThan24bits == EIGHTBIT) {
307 b1 = binaryData[dataIndex];
308 k = (byte) (b1 & 0x03);
309 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
310 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
311 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
312 encodedData[encodedIndex + 2] = PAD;
313 encodedData[encodedIndex + 3] = PAD;
314 } else if (fewerThan24bits == SIXTEENBIT) {
315
316 b1 = binaryData[dataIndex];
317 b2 = binaryData[dataIndex + 1];
318 l = (byte) (b2 & 0x0f);
319 k = (byte) (b1 & 0x03);
320
321 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
322 byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
323
324 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
325 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | (k << 4)];
326 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
327 encodedData[encodedIndex + 3] = PAD;
328 }
329
330 if (isChunked) {
331
332 if (chunksSoFar < nbrChunks) {
333 System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedDataLength - CHUNK_SEPARATOR.length,
334 CHUNK_SEPARATOR.length);
335 }
336 }
337
338 return encodedData;
339 }
340
341
342
343
344
345
346
347 public static byte[] decodeBase64(byte[] base64Data) {
348
349 base64Data = discardNonBase64(base64Data);
350
351
352 if (base64Data.length == 0) {
353 return new byte[0];
354 }
355
356 int numberQuadruple = base64Data.length / FOURBYTE;
357 byte decodedData[] = null;
358 byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
359
360
361
362 int encodedIndex = 0;
363 int dataIndex = 0;
364 {
365
366 int lastData = base64Data.length;
367
368 while (base64Data[lastData - 1] == PAD) {
369 if (--lastData == 0) {
370 return new byte[0];
371 }
372 }
373 decodedData = new byte[lastData - numberQuadruple];
374 }
375
376 for (int i = 0; i < numberQuadruple; i++) {
377 dataIndex = i * 4;
378 marker0 = base64Data[dataIndex + 2];
379 marker1 = base64Data[dataIndex + 3];
380
381 b1 = base64Alphabet[base64Data[dataIndex]];
382 b2 = base64Alphabet[base64Data[dataIndex + 1]];
383
384 if (marker0 != PAD && marker1 != PAD) {
385
386 b3 = base64Alphabet[marker0];
387 b4 = base64Alphabet[marker1];
388
389 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
390 decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
391 decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
392 } else if (marker0 == PAD) {
393
394 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
395 } else if (marker1 == PAD) {
396
397 b3 = base64Alphabet[marker0];
398
399 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
400 decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
401 }
402 encodedIndex += 3;
403 }
404 return decodedData;
405 }
406
407
408
409
410
411
412
413
414 static byte[] discardWhitespace(byte[] data) {
415 byte groomedData[] = new byte[data.length];
416 int bytesCopied = 0;
417
418 for (int i = 0; i < data.length; i++) {
419 switch (data[i]) {
420 case (byte) ' ':
421 case (byte) '\n':
422 case (byte) '\r':
423 case (byte) '\t':
424 break;
425 default:
426 groomedData[bytesCopied++] = data[i];
427 }
428 }
429
430 byte packedData[] = new byte[bytesCopied];
431
432 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
433
434 return packedData;
435 }
436
437
438
439
440
441
442
443
444
445
446 static byte[] discardNonBase64(byte[] data) {
447 byte groomedData[] = new byte[data.length];
448 int bytesCopied = 0;
449
450 for (int i = 0; i < data.length; i++) {
451 if (isBase64(data[i])) {
452 groomedData[bytesCopied++] = data[i];
453 }
454 }
455
456 byte packedData[] = new byte[bytesCopied];
457
458 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
459
460 return packedData;
461 }
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477 public Object encode(Object pObject) {
478 if (!(pObject instanceof byte[])) {
479 throw new InvalidParameterException("Parameter supplied to Base64 encode is not a byte[]");
480 }
481 return encode((byte[]) pObject);
482 }
483
484
485
486
487
488
489
490
491 public byte[] encode(byte[] pArray) {
492 return encodeBase64(pArray, false);
493 }
494
495 }