1 8 9 package mx4j.util; 10 11 18 public class Base64Codec 19 { 20 static final int CHUNK_SIZE = 76; 21 static final byte[] CHUNK_SEPARATOR = "\n".getBytes(); 22 23 static final int BASELENGTH = 255; 24 static final int LOOKUPLENGTH = 64; 25 static final int TWENTYFOURBITGROUP = 24; 26 static final int EIGHTBIT = 8; 27 static final int SIXTEENBIT = 16; 28 static final int SIXBIT = 6; 29 static final int FOURBYTE = 4; 30 static final int SIGN = -128; 31 static final byte PAD = (byte)'='; 32 33 private static byte[] base64Alphabet = new byte[BASELENGTH]; 34 private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; 35 36 static 37 { 38 for (int i = 0; i < BASELENGTH; i++) 39 { 40 base64Alphabet[i] = (byte)-1; 41 } 42 for (int i = 'Z'; i >= 'A'; i--) 43 { 44 base64Alphabet[i] = (byte)(i - 'A'); 45 } 46 for (int i = 'z'; i >= 'a'; i--) 47 { 48 base64Alphabet[i] = (byte)(i - 'a' + 26); 49 } 50 for (int i = '9'; i >= '0'; i--) 51 { 52 base64Alphabet[i] = (byte)(i - '0' + 52); 53 } 54 55 base64Alphabet['+'] = 62; 56 base64Alphabet['/'] = 63; 57 58 for (int i = 0; i <= 25; i++) 59 { 60 lookUpBase64Alphabet[i] = (byte)('A' + i); 61 } 62 63 for (int i = 26, j = 0; i <= 51; i++, j++) 64 { 65 lookUpBase64Alphabet[i] = (byte)('a' + j); 66 } 67 68 for (int i = 52, j = 0; i <= 61; i++, j++) 69 { 70 lookUpBase64Alphabet[i] = (byte)('0' + j); 71 } 72 73 lookUpBase64Alphabet[62] = (byte)'+'; 74 lookUpBase64Alphabet[63] = (byte)'/'; 75 } 76 77 private Base64Codec() 78 { 79 } 80 81 public static boolean isArrayByteBase64(byte[] arrayOctect) 82 { 83 arrayOctect = discardWhitespace(arrayOctect); 84 85 int length = arrayOctect.length; 86 if (length == 0) 87 { 88 return true; 89 } 90 for (int i = 0; i < length; i++) 91 { 92 if (!isBase64(arrayOctect[i])) 93 { 94 return false; 95 } 96 } 97 return true; 98 } 99 100 public static byte[] encodeBase64(byte[] binaryData) 101 { 102 return (encodeBase64(binaryData, false)); 103 } 104 105 public static byte[] decodeBase64(byte[] base64Data) 106 { 107 base64Data = discardWhitespace(base64Data); 110 111 if (base64Data.length == 0) 113 { 114 return new byte[0]; 115 } 116 117 int numberQuadruple = base64Data.length / FOURBYTE; 118 byte decodedData[] = null; 119 byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; 120 121 123 int encodedIndex = 0; 124 int dataIndex = 0; 125 { 126 int lastData = base64Data.length; 128 while (base64Data[lastData - 1] == PAD) 130 { 131 if (--lastData == 0) 132 { 133 return new byte[0]; 134 } 135 } 136 decodedData = new byte[lastData - numberQuadruple]; 137 } 138 139 for (int i = 0; i < numberQuadruple; i++) 140 { 141 dataIndex = i * 4; 142 marker0 = base64Data[dataIndex + 2]; 143 marker1 = base64Data[dataIndex + 3]; 144 145 b1 = base64Alphabet[base64Data[dataIndex]]; 146 b2 = base64Alphabet[base64Data[dataIndex + 1]]; 147 148 if (marker0 != PAD && marker1 != PAD) 149 { 150 b3 = base64Alphabet[marker0]; 152 b4 = base64Alphabet[marker1]; 153 154 decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4); 155 decodedData[encodedIndex + 1] = 156 (byte)(((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 157 decodedData[encodedIndex + 2] = (byte)(b3 << 6 | b4); 158 } 159 else if (marker0 == PAD) 160 { 161 decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4); 163 } 164 else if (marker1 == PAD) 165 { 166 b3 = base64Alphabet[marker0]; 168 169 decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4); 170 decodedData[encodedIndex + 1] = 171 (byte)(((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 172 } 173 encodedIndex += 3; 174 } 175 return decodedData; 176 } 177 178 private static byte[] encodeBase64Chunked(byte[] binaryData) 179 { 180 return (encodeBase64(binaryData, true)); 181 } 182 183 private static boolean isBase64(byte octect) 184 { 185 if (octect == PAD) 186 { 187 return true; 188 } 189 else if (base64Alphabet[octect] == -1) 190 { 191 return false; 192 } 193 else 194 { 195 return true; 196 } 197 } 198 199 private static byte[] encodeBase64(byte[] binaryData, boolean isChunked) 200 { 201 int lengthDataBits = binaryData.length * EIGHTBIT; 202 int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; 203 int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; 204 byte encodedData[] = null; 205 int encodedDataLength = 0; 206 int nbrChunks = 0; 207 208 if (fewerThan24bits != 0) 209 { 210 encodedDataLength = (numberTriplets + 1) * 4; 212 } 213 else 214 { 215 encodedDataLength = numberTriplets * 4; 217 } 218 219 if (isChunked) 223 { 224 225 nbrChunks = 226 (CHUNK_SEPARATOR.length == 0 227 ? 0 228 : (int)Math.ceil((float)encodedDataLength / CHUNK_SIZE)); 229 encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length; 230 } 231 232 encodedData = new byte[encodedDataLength]; 233 234 byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; 235 236 int encodedIndex = 0; 237 int dataIndex = 0; 238 int i = 0; 239 int nextSeparatorIndex = CHUNK_SIZE; 240 int chunksSoFar = 0; 241 242 for (i = 0; i < numberTriplets; i++) 244 { 245 dataIndex = i * 3; 246 b1 = binaryData[dataIndex]; 247 b2 = binaryData[dataIndex + 1]; 248 b3 = binaryData[dataIndex + 2]; 249 250 252 l = (byte)(b2 & 0x0f); 253 k = (byte)(b1 & 0x03); 254 255 byte val1 = 256 ((b1 & SIGN) == 0) 257 ? (byte)(b1 >> 2) 258 : (byte)((b1) >> 2 ^ 0xc0); 259 byte val2 = 260 ((b2 & SIGN) == 0) 261 ? (byte)(b2 >> 4) 262 : (byte)((b2) >> 4 ^ 0xf0); 263 byte val3 = 264 ((b3 & SIGN) == 0) 265 ? (byte)(b3 >> 6) 266 : (byte)((b3) >> 6 ^ 0xfc); 267 268 encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 269 encodedData[encodedIndex + 1] = 273 lookUpBase64Alphabet[val2 | (k << 4)]; 274 encodedData[encodedIndex + 2] = 275 lookUpBase64Alphabet[(l << 2) | val3]; 276 encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f]; 277 278 encodedIndex += 4; 279 280 if (isChunked) 282 { 283 if (encodedIndex == nextSeparatorIndex) 285 { 286 System.arraycopy(CHUNK_SEPARATOR, 287 0, 288 encodedData, 289 encodedIndex, 290 CHUNK_SEPARATOR.length); 291 chunksSoFar++; 292 nextSeparatorIndex = 293 (CHUNK_SIZE * (chunksSoFar + 1)) 294 + (chunksSoFar * CHUNK_SEPARATOR.length); 295 encodedIndex += CHUNK_SEPARATOR.length; 296 } 297 } 298 } 299 300 dataIndex = i * 3; 302 303 if (fewerThan24bits == EIGHTBIT) 304 { 305 b1 = binaryData[dataIndex]; 306 k = (byte)(b1 & 0x03); 307 byte val1 = 310 ((b1 & SIGN) == 0) 311 ? (byte)(b1 >> 2) 312 : (byte)((b1) >> 2 ^ 0xc0); 313 encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 314 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4]; 315 encodedData[encodedIndex + 2] = PAD; 316 encodedData[encodedIndex + 3] = PAD; 317 } 318 else if (fewerThan24bits == SIXTEENBIT) 319 { 320 321 b1 = binaryData[dataIndex]; 322 b2 = binaryData[dataIndex + 1]; 323 l = (byte)(b2 & 0x0f); 324 k = (byte)(b1 & 0x03); 325 326 byte val1 = 327 ((b1 & SIGN) == 0) 328 ? (byte)(b1 >> 2) 329 : (byte)((b1) >> 2 ^ 0xc0); 330 byte val2 = 331 ((b2 & SIGN) == 0) 332 ? (byte)(b2 >> 4) 333 : (byte)((b2) >> 4 ^ 0xf0); 334 335 encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 336 encodedData[encodedIndex + 1] = 337 lookUpBase64Alphabet[val2 | (k << 4)]; 338 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2]; 339 encodedData[encodedIndex + 3] = PAD; 340 } 341 342 if (isChunked) 343 { 344 if (chunksSoFar < nbrChunks) 346 { 347 System.arraycopy(CHUNK_SEPARATOR, 348 0, 349 encodedData, 350 encodedDataLength - CHUNK_SEPARATOR.length, 351 CHUNK_SEPARATOR.length); 352 } 353 } 354 355 return encodedData; 356 } 357 358 private static byte[] discardWhitespace(byte[] data) 359 { 360 byte groomedData[] = new byte[data.length]; 361 int bytesCopied = 0; 362 363 for (int i = 0; i < data.length; i++) 364 { 365 switch (data[i]) 366 { 367 case (byte)' ': 368 case (byte)'\n': 369 case (byte)'\r': 370 case (byte)'\t': 371 break; 372 default: 373 groomedData[bytesCopied++] = data[i]; 374 } 375 } 376 377 byte packedData[] = new byte[bytesCopied]; 378 379 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); 380 381 return packedData; 382 } 383 } 384 | Popular Tags |