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(
209 "Parameter supplied to Base64 decode is not a byte[]");
210 }
211 return decode((byte[]) pObject);
212 }
213
214
215
216
217
218
219
220
221 public byte[] decode(byte[] pArray) {
222 return decodeBase64(pArray);
223 }
224
225
226
227
228
229
230
231
232
233
234 public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {
235 int lengthDataBits = binaryData.length * EIGHTBIT;
236 int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
237 int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
238 byte encodedData[] = null;
239 int encodedDataLength = 0;
240 int nbrChunks = 0;
241
242 if (fewerThan24bits != 0) {
243
244 encodedDataLength = (numberTriplets + 1) * 4;
245 } else {
246
247 encodedDataLength = numberTriplets * 4;
248 }
249
250
251
252
253 if (isChunked) {
254
255 nbrChunks = (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math
256 .ceil((float) encodedDataLength / CHUNK_SIZE));
257 encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
258 }
259
260 encodedData = new byte[encodedDataLength];
261
262 byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
263
264 int encodedIndex = 0;
265 int dataIndex = 0;
266 int i = 0;
267 int nextSeparatorIndex = CHUNK_SIZE;
268 int chunksSoFar = 0;
269
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
278
279 l = (byte) (b2 & 0x0f);
280 k = (byte) (b1 & 0x03);
281
282 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
283 : (byte) ((b1) >> 2 ^ 0xc0);
284 byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
285 : (byte) ((b2) >> 4 ^ 0xf0);
286 byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
287 : (byte) ((b3) >> 6 ^ 0xfc);
288
289 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
290
291
292
293 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2
294 | (k << 4)];
295 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[(l << 2)
296 | val3];
297 encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
298
299 encodedIndex += 4;
300
301
302 if (isChunked) {
303
304 if (encodedIndex == nextSeparatorIndex) {
305 System.arraycopy(CHUNK_SEPARATOR, 0, encodedData,
306 encodedIndex, CHUNK_SEPARATOR.length);
307 chunksSoFar++;
308 nextSeparatorIndex = (CHUNK_SIZE * (chunksSoFar + 1))
309 + (chunksSoFar * CHUNK_SEPARATOR.length);
310 encodedIndex += CHUNK_SEPARATOR.length;
311 }
312 }
313 }
314
315
316 dataIndex = i * 3;
317
318 if (fewerThan24bits == EIGHTBIT) {
319 b1 = binaryData[dataIndex];
320 k = (byte) (b1 & 0x03);
321
322
323 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
324 : (byte) ((b1) >> 2 ^ 0xc0);
325 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
326 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
327 encodedData[encodedIndex + 2] = PAD;
328 encodedData[encodedIndex + 3] = PAD;
329 } else if (fewerThan24bits == SIXTEENBIT) {
330
331 b1 = binaryData[dataIndex];
332 b2 = binaryData[dataIndex + 1];
333 l = (byte) (b2 & 0x0f);
334 k = (byte) (b1 & 0x03);
335
336 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
337 : (byte) ((b1) >> 2 ^ 0xc0);
338 byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
339 : (byte) ((b2) >> 4 ^ 0xf0);
340
341 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
342 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2
343 | (k << 4)];
344 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
345 encodedData[encodedIndex + 3] = PAD;
346 }
347
348 if (isChunked) {
349
350 if (chunksSoFar < nbrChunks) {
351 System.arraycopy(CHUNK_SEPARATOR, 0, encodedData,
352 encodedDataLength - CHUNK_SEPARATOR.length,
353 CHUNK_SEPARATOR.length);
354 }
355 }
356
357 return encodedData;
358 }
359
360
361
362
363
364
365
366 public static byte[] decodeBase64(byte[] base64Data) {
367
368 base64Data = discardNonBase64(base64Data);
369
370
371 if (base64Data.length == 0) {
372 return new byte[0];
373 }
374
375 int numberQuadruple = base64Data.length / FOURBYTE;
376 byte decodedData[] = null;
377 byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
378
379
380
381 int encodedIndex = 0;
382 int dataIndex = 0;
383 {
384
385 int lastData = base64Data.length;
386
387 while (base64Data[lastData - 1] == PAD) {
388 if (--lastData == 0) {
389 return new byte[0];
390 }
391 }
392 decodedData = new byte[lastData - numberQuadruple];
393 }
394
395 for (int i = 0; i < numberQuadruple; i++) {
396 dataIndex = i * 4;
397 marker0 = base64Data[dataIndex + 2];
398 marker1 = base64Data[dataIndex + 3];
399
400 b1 = base64Alphabet[base64Data[dataIndex]];
401 b2 = base64Alphabet[base64Data[dataIndex + 1]];
402
403 if (marker0 != PAD && marker1 != PAD) {
404
405 b3 = base64Alphabet[marker0];
406 b4 = base64Alphabet[marker1];
407
408 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
409 decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
410 decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
411 } else if (marker0 == PAD) {
412
413 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
414 } else if (marker1 == PAD) {
415
416 b3 = base64Alphabet[marker0];
417
418 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
419 decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
420 }
421 encodedIndex += 3;
422 }
423 return decodedData;
424 }
425
426
427
428
429
430
431
432
433 static byte[] discardWhitespace(byte[] data) {
434 byte groomedData[] = new byte[data.length];
435 int bytesCopied = 0;
436
437 for (int i = 0; i < data.length; i++) {
438 switch (data[i]) {
439 case (byte) ' ':
440 case (byte) '\n':
441 case (byte) '\r':
442 case (byte) '\t':
443 break;
444 default:
445 groomedData[bytesCopied++] = data[i];
446 }
447 }
448
449 byte packedData[] = new byte[bytesCopied];
450
451 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
452
453 return packedData;
454 }
455
456
457
458
459
460
461
462
463
464
465 static byte[] discardNonBase64(byte[] data) {
466 byte groomedData[] = new byte[data.length];
467 int bytesCopied = 0;
468
469 for (int i = 0; i < data.length; i++) {
470 if (isBase64(data[i])) {
471 groomedData[bytesCopied++] = data[i];
472 }
473 }
474
475 byte packedData[] = new byte[bytesCopied];
476
477 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
478
479 return packedData;
480 }
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496 public Object encode(Object pObject) {
497 if (!(pObject instanceof byte[])) {
498 throw new InvalidParameterException(
499 "Parameter supplied to Base64 encode is not a byte[]");
500 }
501 return encode((byte[]) pObject);
502 }
503
504
505
506
507
508
509
510
511 public byte[] encode(byte[] pArray) {
512 return encodeBase64(pArray, false);
513 }
514
515 }