21 | * I am placing this code in the Public Domain. Do with it as you will. 22 | * This software comes with no guarantees or warranties but with 23 | * plenty of well-wishing instead! 24 | * Please visit 25 | * http://iharder.net/xmlizable 26 | * periodically to check for updates or to contribute improvements. 27 | *
28 | * 29 | * @author Robert Harder 30 | * @author rharder@usa.net 31 | * @version 1.3 32 | */ 33 | 34 | /** 35 | * Base64 converter class. This code is not a complete MIME encoder; 36 | * it simply converts binary data to base64 data and back. 37 | * 38 | *Note {@link CharBase64} is a GWT-compatible implementation of this 39 | * class. 40 | */ 41 | public class Base64 { 42 | /** Specify encoding (value is {@code true}). */ 43 | public final static boolean ENCODE = true; 44 | 45 | /** Specify decoding (value is {@code false}). */ 46 | public final static boolean DECODE = false; 47 | 48 | /** The equals sign (=) as a byte. */ 49 | private final static byte EQUALS_SIGN = (byte) '='; 50 | 51 | /** The new line character (\n) as a byte. */ 52 | private final static byte NEW_LINE = (byte) '\n'; 53 | 54 | /** 55 | * The 64 valid Base64 values. 56 | */ 57 | private final static byte[] ALPHABET = 58 | {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', 59 | (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', 60 | (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', 61 | (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', 62 | (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', 63 | (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', 64 | (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', 65 | (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', 66 | (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', 67 | (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', 68 | (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', 69 | (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', 70 | (byte) '9', (byte) '+', (byte) '/'}; 71 | 72 | /** 73 | * The 64 valid web safe Base64 values. 74 | */ 75 | private final static byte[] WEBSAFE_ALPHABET = 76 | {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', 77 | (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', 78 | (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', 79 | (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', 80 | (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', 81 | (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', 82 | (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', 83 | (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', 84 | (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', 85 | (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', 86 | (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', 87 | (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', 88 | (byte) '9', (byte) '-', (byte) '_'}; 89 | 90 | /** 91 | * Translates a Base64 value to either its 6-bit reconstruction value 92 | * or a negative number indicating some other meaning. 93 | **/ 94 | private final static byte[] DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 95 | -5, -5, // Whitespace: Tab and Linefeed 96 | -9, -9, // Decimal 11 - 12 97 | -5, // Whitespace: Carriage Return 98 | -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 99 | -9, -9, -9, -9, -9, // Decimal 27 - 31 100 | -5, // Whitespace: Space 101 | -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 102 | 62, // Plus sign at decimal 43 103 | -9, -9, -9, // Decimal 44 - 46 104 | 63, // Slash at decimal 47 105 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine 106 | -9, -9, -9, // Decimal 58 - 60 107 | -1, // Equals sign at decimal 61 108 | -9, -9, -9, // Decimal 62 - 64 109 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' 110 | 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' 111 | -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 112 | 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' 113 | 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' 114 | -9, -9, -9, -9, -9 // Decimal 123 - 127 115 | /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 116 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 117 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 118 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 119 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 120 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 121 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 122 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 123 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 124 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ 125 | }; 126 | 127 | /** The web safe decodabet */ 128 | private final static byte[] WEBSAFE_DECODABET = 129 | {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 130 | -5, -5, // Whitespace: Tab and Linefeed 131 | -9, -9, // Decimal 11 - 12 132 | -5, // Whitespace: Carriage Return 133 | -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 134 | -9, -9, -9, -9, -9, // Decimal 27 - 31 135 | -5, // Whitespace: Space 136 | -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 44 137 | 62, // Dash '-' sign at decimal 45 138 | -9, -9, // Decimal 46-47 139 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine 140 | -9, -9, -9, // Decimal 58 - 60 141 | -1, // Equals sign at decimal 61 142 | -9, -9, -9, // Decimal 62 - 64 143 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' 144 | 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' 145 | -9, -9, -9, -9, // Decimal 91-94 146 | 63, // Underscore '_' at decimal 95 147 | -9, // Decimal 96 148 | 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' 149 | 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' 150 | -9, -9, -9, -9, -9 // Decimal 123 - 127 151 | /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 152 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 153 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 154 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 155 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 156 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 157 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 158 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 159 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 160 | -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ 161 | }; 162 | 163 | // Indicates white space in encoding 164 | private final static byte WHITE_SPACE_ENC = -5; 165 | // Indicates equals sign in encoding 166 | private final static byte EQUALS_SIGN_ENC = -1; 167 | 168 | /** Defeats instantiation. */ 169 | private Base64() { 170 | } 171 | 172 | /* ******** E N C O D I N G M E T H O D S ******** */ 173 | 174 | /** 175 | * Encodes up to three bytes of the array source 176 | * and writes the resulting four Base64 bytes to destination. 177 | * The source and destination arrays can be manipulated 178 | * anywhere along their length by specifying 179 | * srcOffset and destOffset. 180 | * This method does not check to make sure your arrays 181 | * are large enough to accommodate srcOffset + 3 for 182 | * the source array or destOffset + 4 for 183 | * the destination array. 184 | * The actual number of significant bytes in your array is 185 | * given by numSigBytes. 186 | * 187 | * @param source the array to convert 188 | * @param srcOffset the index where conversion begins 189 | * @param numSigBytes the number of significant bytes in your array 190 | * @param destination the array to hold the conversion 191 | * @param destOffset the index where output will be put 192 | * @param alphabet is the encoding alphabet 193 | * @return the destination array 194 | * @since 1.3 195 | */ 196 | private static byte[] encode3to4(byte[] source, int srcOffset, 197 | int numSigBytes, byte[] destination, int destOffset, byte[] alphabet) { 198 | // 1 2 3 199 | // 01234567890123456789012345678901 Bit position 200 | // --------000000001111111122222222 Array position from threeBytes 201 | // --------| || || || | Six bit groups to index alphabet 202 | // >>18 >>12 >> 6 >> 0 Right shift necessary 203 | // 0x3f 0x3f 0x3f Additional AND 204 | 205 | // Create buffer with zero-padding if there are only one or two 206 | // significant bytes passed in the array. 207 | // We have to shift left 24 in order to flush out the 1's that appear 208 | // when Java treats a value as negative that is cast from a byte to an int. 209 | int inBuff = 210 | (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) 211 | | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) 212 | | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); 213 | 214 | switch (numSigBytes) { 215 | case 3: 216 | destination[destOffset] = alphabet[(inBuff >>> 18)]; 217 | destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; 218 | destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; 219 | destination[destOffset + 3] = alphabet[(inBuff) & 0x3f]; 220 | return destination; 221 | case 2: 222 | destination[destOffset] = alphabet[(inBuff >>> 18)]; 223 | destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; 224 | destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; 225 | destination[destOffset + 3] = EQUALS_SIGN; 226 | return destination; 227 | case 1: 228 | destination[destOffset] = alphabet[(inBuff >>> 18)]; 229 | destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; 230 | destination[destOffset + 2] = EQUALS_SIGN; 231 | destination[destOffset + 3] = EQUALS_SIGN; 232 | return destination; 233 | default: 234 | return destination; 235 | } // end switch 236 | } // end encode3to4 237 | 238 | /** 239 | * Encodes a byte array into Base64 notation. 240 | * Equivalent to calling 241 | * {@code encodeBytes(source, 0, source.length)} 242 | * 243 | * @param source The data to convert 244 | * @since 1.4 245 | */ 246 | public static String encode(byte[] source) { 247 | return encode(source, 0, source.length, ALPHABET, true); 248 | } 249 | 250 | /** 251 | * Encodes a byte array into web safe Base64 notation. 252 | * 253 | * @param source The data to convert 254 | * @param doPadding is {@code true} to pad result with '=' chars 255 | * if it does not fall on 3 byte boundaries 256 | */ 257 | public static String encodeWebSafe(byte[] source, boolean doPadding) { 258 | return encode(source, 0, source.length, WEBSAFE_ALPHABET, doPadding); 259 | } 260 | 261 | /** 262 | * Encodes a byte array into Base64 notation. 263 | * 264 | * @param source the data to convert 265 | * @param off offset in array where conversion should begin 266 | * @param len length of data to convert 267 | * @param alphabet the encoding alphabet 268 | * @param doPadding is {@code true} to pad result with '=' chars 269 | * if it does not fall on 3 byte boundaries 270 | * @since 1.4 271 | */ 272 | public static String encode(byte[] source, int off, int len, byte[] alphabet, 273 | boolean doPadding) { 274 | byte[] outBuff = encode(source, off, len, alphabet, Integer.MAX_VALUE); 275 | int outLen = outBuff.length; 276 | 277 | // If doPadding is false, set length to truncate '=' 278 | // padding characters 279 | while (doPadding == false && outLen > 0) { 280 | if (outBuff[outLen - 1] != '=') { 281 | break; 282 | } 283 | outLen -= 1; 284 | } 285 | 286 | return new String(outBuff, 0, outLen); 287 | } 288 | 289 | /** 290 | * Encodes a byte array into Base64 notation. 291 | * 292 | * @param source the data to convert 293 | * @param off offset in array where conversion should begin 294 | * @param len length of data to convert 295 | * @param alphabet is the encoding alphabet 296 | * @param maxLineLength maximum length of one line. 297 | * @return the BASE64-encoded byte array 298 | */ 299 | public static byte[] encode(byte[] source, int off, int len, byte[] alphabet, 300 | int maxLineLength) { 301 | int lenDiv3 = (len + 2) / 3; // ceil(len / 3) 302 | int len43 = lenDiv3 * 4; 303 | byte[] outBuff = new byte[len43 // Main 4:3 304 | + (len43 / maxLineLength)]; // New lines 305 | 306 | int d = 0; 307 | int e = 0; 308 | int len2 = len - 2; 309 | int lineLength = 0; 310 | for (; d < len2; d += 3, e += 4) { 311 | 312 | // The following block of code is the same as 313 | // encode3to4( source, d + off, 3, outBuff, e, alphabet ); 314 | // but inlined for faster encoding (~20% improvement) 315 | int inBuff = 316 | ((source[d + off] << 24) >>> 8) 317 | | ((source[d + 1 + off] << 24) >>> 16) 318 | | ((source[d + 2 + off] << 24) >>> 24); 319 | outBuff[e] = alphabet[(inBuff >>> 18)]; 320 | outBuff[e + 1] = alphabet[(inBuff >>> 12) & 0x3f]; 321 | outBuff[e + 2] = alphabet[(inBuff >>> 6) & 0x3f]; 322 | outBuff[e + 3] = alphabet[(inBuff) & 0x3f]; 323 | 324 | lineLength += 4; 325 | if (lineLength == maxLineLength) { 326 | outBuff[e + 4] = NEW_LINE; 327 | e++; 328 | lineLength = 0; 329 | } // end if: end of line 330 | } // end for: each piece of array 331 | 332 | if (d < len) { 333 | encode3to4(source, d + off, len - d, outBuff, e, alphabet); 334 | 335 | lineLength += 4; 336 | if (lineLength == maxLineLength) { 337 | // Add a last newline 338 | outBuff[e + 4] = NEW_LINE; 339 | e++; 340 | } 341 | e += 4; 342 | } 343 | 344 | assert (e == outBuff.length); 345 | return outBuff; 346 | } 347 | 348 | 349 | /* ******** D E C O D I N G M E T H O D S ******** */ 350 | 351 | 352 | /** 353 | * Decodes four bytes from array source 354 | * and writes the resulting bytes (up to three of them) 355 | * to destination. 356 | * The source and destination arrays can be manipulated 357 | * anywhere along their length by specifying 358 | * srcOffset and destOffset. 359 | * This method does not check to make sure your arrays 360 | * are large enough to accommodate srcOffset + 4 for 361 | * the source array or destOffset + 3 for 362 | * the destination array. 363 | * This method returns the actual number of bytes that 364 | * were converted from the Base64 encoding. 365 | * 366 | * 367 | * @param source the array to convert 368 | * @param srcOffset the index where conversion begins 369 | * @param destination the array to hold the conversion 370 | * @param destOffset the index where output will be put 371 | * @param decodabet the decodabet for decoding Base64 content 372 | * @return the number of decoded bytes converted 373 | * @since 1.3 374 | */ 375 | private static int decode4to3(byte[] source, int srcOffset, 376 | byte[] destination, int destOffset, byte[] decodabet) { 377 | // Example: Dk== 378 | if (source[srcOffset + 2] == EQUALS_SIGN) { 379 | int outBuff = 380 | ((decodabet[source[srcOffset]] << 24) >>> 6) 381 | | ((decodabet[source[srcOffset + 1]] << 24) >>> 12); 382 | 383 | destination[destOffset] = (byte) (outBuff >>> 16); 384 | return 1; 385 | } else if (source[srcOffset + 3] == EQUALS_SIGN) { 386 | // Example: DkL= 387 | int outBuff = 388 | ((decodabet[source[srcOffset]] << 24) >>> 6) 389 | | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) 390 | | ((decodabet[source[srcOffset + 2]] << 24) >>> 18); 391 | 392 | destination[destOffset] = (byte) (outBuff >>> 16); 393 | destination[destOffset + 1] = (byte) (outBuff >>> 8); 394 | return 2; 395 | } else { 396 | // Example: DkLE 397 | int outBuff = 398 | ((decodabet[source[srcOffset]] << 24) >>> 6) 399 | | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) 400 | | ((decodabet[source[srcOffset + 2]] << 24) >>> 18) 401 | | ((decodabet[source[srcOffset + 3]] << 24) >>> 24); 402 | 403 | destination[destOffset] = (byte) (outBuff >> 16); 404 | destination[destOffset + 1] = (byte) (outBuff >> 8); 405 | destination[destOffset + 2] = (byte) (outBuff); 406 | return 3; 407 | } 408 | } // end decodeToBytes 409 | 410 | 411 | /** 412 | * Decodes data from Base64 notation. 413 | * 414 | * @param s the string to decode (decoded in default encoding) 415 | * @return the decoded data 416 | * @since 1.4 417 | */ 418 | public static byte[] decode(String s) throws Base64DecoderException { 419 | byte[] bytes = s.getBytes(); 420 | return decode(bytes, 0, bytes.length); 421 | } 422 | 423 | /** 424 | * Decodes data from web safe Base64 notation. 425 | * Web safe encoding uses '-' instead of '+', '_' instead of '/' 426 | * 427 | * @param s the string to decode (decoded in default encoding) 428 | * @return the decoded data 429 | */ 430 | public static byte[] decodeWebSafe(String s) throws Base64DecoderException { 431 | byte[] bytes = s.getBytes(); 432 | return decodeWebSafe(bytes, 0, bytes.length); 433 | } 434 | 435 | /** 436 | * Decodes Base64 content in byte array format and returns 437 | * the decoded byte array. 438 | * 439 | * @param source The Base64 encoded data 440 | * @return decoded data 441 | * @since 1.3 442 | * @throws Base64DecoderException 443 | */ 444 | public static byte[] decode(byte[] source) throws Base64DecoderException { 445 | return decode(source, 0, source.length); 446 | } 447 | 448 | /** 449 | * Decodes web safe Base64 content in byte array format and returns 450 | * the decoded data. 451 | * Web safe encoding uses '-' instead of '+', '_' instead of '/' 452 | * 453 | * @param source the string to decode (decoded in default encoding) 454 | * @return the decoded data 455 | */ 456 | public static byte[] decodeWebSafe(byte[] source) 457 | throws Base64DecoderException { 458 | return decodeWebSafe(source, 0, source.length); 459 | } 460 | 461 | /** 462 | * Decodes Base64 content in byte array format and returns 463 | * the decoded byte array. 464 | * 465 | * @param source the Base64 encoded data 466 | * @param off the offset of where to begin decoding 467 | * @param len the length of characters to decode 468 | * @return decoded data 469 | * @since 1.3 470 | * @throws Base64DecoderException 471 | */ 472 | public static byte[] decode(byte[] source, int off, int len) 473 | throws Base64DecoderException { 474 | return decode(source, off, len, DECODABET); 475 | } 476 | 477 | /** 478 | * Decodes web safe Base64 content in byte array format and returns 479 | * the decoded byte array. 480 | * Web safe encoding uses '-' instead of '+', '_' instead of '/' 481 | * 482 | * @param source the Base64 encoded data 483 | * @param off the offset of where to begin decoding 484 | * @param len the length of characters to decode 485 | * @return decoded data 486 | */ 487 | public static byte[] decodeWebSafe(byte[] source, int off, int len) 488 | throws Base64DecoderException { 489 | return decode(source, off, len, WEBSAFE_DECODABET); 490 | } 491 | 492 | /** 493 | * Decodes Base64 content using the supplied decodabet and returns 494 | * the decoded byte array. 495 | * 496 | * @param source the Base64 encoded data 497 | * @param off the offset of where to begin decoding 498 | * @param len the length of characters to decode 499 | * @param decodabet the decodabet for decoding Base64 content 500 | * @return decoded data 501 | */ 502 | public static byte[] decode(byte[] source, int off, int len, byte[] decodabet) 503 | throws Base64DecoderException { 504 | int len34 = len * 3 / 4; 505 | byte[] outBuff = new byte[2 + len34]; // Upper limit on size of output 506 | int outBuffPosn = 0; 507 | 508 | byte[] b4 = new byte[4]; 509 | int b4Posn = 0; 510 | int i = 0; 511 | byte sbiCrop = 0; 512 | byte sbiDecode = 0; 513 | for (i = 0; i < len; i++) { 514 | sbiCrop = (byte) (source[i + off] & 0x7f); // Only the low seven bits 515 | sbiDecode = decodabet[sbiCrop]; 516 | 517 | if (sbiDecode >= WHITE_SPACE_ENC) { // White space Equals sign or better 518 | if (sbiDecode >= EQUALS_SIGN_ENC) { 519 | // An equals sign (for padding) must not occur at position 0 or 1 520 | // and must be the last byte[s] in the encoded value 521 | if (sbiCrop == EQUALS_SIGN) { 522 | int bytesLeft = len - i; 523 | byte lastByte = (byte) (source[len - 1 + off] & 0x7f); 524 | if (b4Posn == 0 || b4Posn == 1) { 525 | throw new Base64DecoderException( 526 | "invalid padding byte '=' at byte offset " + i); 527 | } else if ((b4Posn == 3 && bytesLeft > 2) 528 | || (b4Posn == 4 && bytesLeft > 1)) { 529 | throw new Base64DecoderException( 530 | "padding byte '=' falsely signals end of encoded value " 531 | + "at offset " + i); 532 | } else if (lastByte != EQUALS_SIGN && lastByte != NEW_LINE) { 533 | throw new Base64DecoderException( 534 | "encoded value has invalid trailing byte"); 535 | } 536 | break; 537 | } 538 | 539 | b4[b4Posn++] = sbiCrop; 540 | if (b4Posn == 4) { 541 | outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); 542 | b4Posn = 0; 543 | } 544 | } 545 | } else { 546 | throw new Base64DecoderException("Bad Base64 input character at " + i 547 | + ": " + source[i + off] + "(decimal)"); 548 | } 549 | } 550 | 551 | // Because web safe encoding allows non padding base64 encodes, we 552 | // need to pad the rest of the b4 buffer with equal signs when 553 | // b4Posn != 0. There can be at most 2 equal signs at the end of 554 | // four characters, so the b4 buffer must have two or three 555 | // characters. This also catches the case where the input is 556 | // padded with EQUALS_SIGN 557 | if (b4Posn != 0) { 558 | if (b4Posn == 1) { 559 | throw new Base64DecoderException("single trailing character at offset " 560 | + (len - 1)); 561 | } 562 | b4[b4Posn++] = EQUALS_SIGN; 563 | outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); 564 | } 565 | 566 | byte[] out = new byte[outBuffPosn]; 567 | System.arraycopy(outBuff, 0, out, 0, outBuffPosn); 568 | return out; 569 | } 570 | } 571 | --------------------------------------------------------------------------------