1 19 20 package org.apache.cayenne.util; 21 22 32 public class Base64Codec { 33 34 43 static final int CHUNK_SIZE = 76; 44 45 50 static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes(); 51 52 55 static final int BASELENGTH = 255; 56 57 60 static final int LOOKUPLENGTH = 64; 61 62 65 static final int EIGHTBIT = 8; 66 67 70 static final int SIXTEENBIT = 16; 71 72 75 static final int TWENTYFOURBITGROUP = 24; 76 77 80 static final int FOURBYTE = 4; 81 82 85 static final int SIGN = -128; 86 87 90 static final byte PAD = (byte) '='; 91 92 private static byte[] base64Alphabet = new byte[BASELENGTH]; 95 private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; 96 97 static { 99 for (int i = 0; i < BASELENGTH; i++) { 100 base64Alphabet[i] = (byte) -1; 101 } 102 for (int i = 'Z'; i >= 'A'; i--) { 103 base64Alphabet[i] = (byte) (i - 'A'); 104 } 105 for (int i = 'z'; i >= 'a'; i--) { 106 base64Alphabet[i] = (byte) (i - 'a' + 26); 107 } 108 for (int i = '9'; i >= '0'; i--) { 109 base64Alphabet[i] = (byte) (i - '0' + 52); 110 } 111 112 base64Alphabet['+'] = 62; 113 base64Alphabet['/'] = 63; 114 115 for (int i = 0; i <= 25; i++) { 116 lookUpBase64Alphabet[i] = (byte) ('A' + i); 117 } 118 119 for (int i = 26, j = 0; i <= 51; i++, j++) { 120 lookUpBase64Alphabet[i] = (byte) ('a' + j); 121 } 122 123 for (int i = 52, j = 0; i <= 61; i++, j++) { 124 lookUpBase64Alphabet[i] = (byte) ('0' + j); 125 } 126 127 lookUpBase64Alphabet[62] = (byte) '+'; 128 lookUpBase64Alphabet[63] = (byte) '/'; 129 } 130 131 private static boolean isBase64(byte octect) { 132 if (octect == PAD) { 133 return true; 134 } 135 else if (base64Alphabet[octect] == -1) { 136 return false; 137 } 138 else { 139 return true; 140 } 141 } 142 143 151 public static boolean isArrayByteBase64(byte[] arrayOctect) { 152 153 arrayOctect = discardWhitespace(arrayOctect); 154 155 int length = arrayOctect.length; 156 if (length == 0) { 157 return true; 160 } 161 for (int i = 0; i < length; i++) { 162 if (!isBase64(arrayOctect[i])) { 163 return false; 164 } 165 } 166 return true; 167 } 168 169 175 public static byte[] encodeBase64(byte[] binaryData) { 176 return encodeBase64(binaryData, false); 177 } 178 179 186 public static byte[] encodeBase64Chunked(byte[] binaryData) { 187 return encodeBase64(binaryData, true); 188 } 189 190 199 public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) { 200 int lengthDataBits = binaryData.length * EIGHTBIT; 201 int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; 202 int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP; 203 byte encodedData[] = null; 204 int encodedDataLength = 0; 205 int nbrChunks = 0; 206 207 if (fewerThan24bits != 0) { 208 encodedDataLength = (numberTriplets + 1) * 4; 210 } 211 else { 212 encodedDataLength = numberTriplets * 4; 214 } 215 216 if (isChunked) { 220 221 nbrChunks = (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math 222 .ceil((float) encodedDataLength / CHUNK_SIZE)); 223 encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length; 224 } 225 226 encodedData = new byte[encodedDataLength]; 227 228 byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; 229 230 int encodedIndex = 0; 231 int dataIndex = 0; 232 int i = 0; 233 int nextSeparatorIndex = CHUNK_SIZE; 234 int chunksSoFar = 0; 235 236 for (i = 0; i < numberTriplets; i++) { 238 dataIndex = i * 3; 239 b1 = binaryData[dataIndex]; 240 b2 = binaryData[dataIndex + 1]; 241 b3 = binaryData[dataIndex + 2]; 242 243 245 l = (byte) (b2 & 0x0f); 246 k = (byte) (b1 & 0x03); 247 248 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 249 byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); 250 byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc); 251 252 encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 253 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | (k << 4)]; 257 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[(l << 2) | val3]; 258 encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f]; 259 260 encodedIndex += 4; 261 262 if (isChunked) { 264 if (encodedIndex == nextSeparatorIndex) { 266 System.arraycopy( 267 CHUNK_SEPARATOR, 268 0, 269 encodedData, 270 encodedIndex, 271 CHUNK_SEPARATOR.length); 272 chunksSoFar++; 273 nextSeparatorIndex = (CHUNK_SIZE * (chunksSoFar + 1)) 274 + (chunksSoFar * CHUNK_SEPARATOR.length); 275 encodedIndex += CHUNK_SEPARATOR.length; 276 } 277 } 278 } 279 280 dataIndex = i * 3; 282 283 if (fewerThan24bits == EIGHTBIT) { 284 b1 = binaryData[dataIndex]; 285 k = (byte) (b1 & 0x03); 286 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 289 encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 290 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4]; 291 encodedData[encodedIndex + 2] = PAD; 292 encodedData[encodedIndex + 3] = PAD; 293 } 294 else if (fewerThan24bits == SIXTEENBIT) { 295 296 b1 = binaryData[dataIndex]; 297 b2 = binaryData[dataIndex + 1]; 298 l = (byte) (b2 & 0x0f); 299 k = (byte) (b1 & 0x03); 300 301 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0); 302 byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0); 303 304 encodedData[encodedIndex] = lookUpBase64Alphabet[val1]; 305 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | (k << 4)]; 306 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2]; 307 encodedData[encodedIndex + 3] = PAD; 308 } 309 310 if (isChunked) { 311 if (chunksSoFar < nbrChunks) { 313 System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedDataLength 314 - CHUNK_SEPARATOR.length, CHUNK_SEPARATOR.length); 315 } 316 } 317 318 return encodedData; 319 } 320 321 327 public static byte[] decodeBase64(byte[] base64Data) { 328 base64Data = discardNonBase64(base64Data); 330 331 if (base64Data.length == 0) { 333 return new byte[0]; 334 } 335 336 int numberQuadruple = base64Data.length / FOURBYTE; 337 byte decodedData[] = null; 338 byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; 339 340 342 int encodedIndex = 0; 343 int dataIndex = 0; 344 { 345 int lastData = base64Data.length; 347 while (base64Data[lastData - 1] == PAD) { 349 if (--lastData == 0) { 350 return new byte[0]; 351 } 352 } 353 decodedData = new byte[lastData - numberQuadruple]; 354 } 355 356 for (int i = 0; i < numberQuadruple; i++) { 357 dataIndex = i * 4; 358 marker0 = base64Data[dataIndex + 2]; 359 marker1 = base64Data[dataIndex + 3]; 360 361 b1 = base64Alphabet[base64Data[dataIndex]]; 362 b2 = base64Alphabet[base64Data[dataIndex + 1]]; 363 364 if (marker0 != PAD && marker1 != PAD) { 365 b3 = base64Alphabet[marker0]; 367 b4 = base64Alphabet[marker1]; 368 369 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 370 decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 371 decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); 372 } 373 else if (marker0 == PAD) { 374 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 376 } 377 else if (marker1 == PAD) { 378 b3 = base64Alphabet[marker0]; 380 381 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 382 decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 383 } 384 encodedIndex += 3; 385 } 386 return decodedData; 387 } 388 389 395 static byte[] discardWhitespace(byte[] data) { 396 byte groomedData[] = new byte[data.length]; 397 int bytesCopied = 0; 398 399 for (int i = 0; i < data.length; i++) { 400 switch (data[i]) { 401 case (byte) ' ': 402 case (byte) '\n': 403 case (byte) '\r': 404 case (byte) '\t': 405 break; 406 default: 407 groomedData[bytesCopied++] = data[i]; 408 } 409 } 410 411 byte packedData[] = new byte[bytesCopied]; 412 413 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); 414 415 return packedData; 416 } 417 418 426 static byte[] discardNonBase64(byte[] data) { 427 byte groomedData[] = new byte[data.length]; 428 int bytesCopied = 0; 429 430 for (int i = 0; i < data.length; i++) { 431 if (isBase64(data[i])) { 432 groomedData[bytesCopied++] = data[i]; 433 } 434 } 435 436 byte packedData[] = new byte[bytesCopied]; 437 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); 438 return packedData; 439 } 440 } 441 | Popular Tags |