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