Here you can find the source of decode(byte[] source, int off, int len)
Parameter | Description |
---|---|
source | The Base64 encoded data |
off | The offset of where to begin decoding |
len | The length of characters to decode |
public static byte[] decode(byte[] source, int off, int len)
//package com.java2s; import java.io.UnsupportedEncodingException; public class Main { private static final int sText = 0; private static final int s1Dig = 1; private static final int s2Dig = 2; private static final int sEscape = 3; private static final int sU1 = 4; private static final int sU2 = 5; private static final int sU3 = 6; private static final int sU4 = 7; /**// w ww . j av a2 s . co m * Translates a Base64 value to either its 6-bit reconstruction value or a negative number indicating some other meaning. */ protected final static byte[] DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 -5, -5, // Whitespace: Tab and Linefeed -9, -9, // Decimal 11 - 12 -5, // Whitespace: Carriage Return -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - // 26 -9, -9, -9, -9, -9, // Decimal 27 - 31 -5, // Whitespace: Space -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 62, // Plus sign at decimal 43 -9, -9, -9, // Decimal 44 - 46 63, // Slash at decimal 47 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine -9, -9, -9, // Decimal 58 - 60 -1, // Equals sign at decimal 61 -9, -9, -9, // Decimal 62 - 64 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' // through 'N' 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' // through 'Z' -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' // through 'm' 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' // through 'z' -9, -9, -9, -9 // Decimal 123 - 126 }; protected final static byte WHITE_SPACE_ENC = -5; protected final static byte EQUALS_SIGN_ENC = -1; /** * The equals sign (=) as a byte. */ protected final static byte EQUALS_SIGN = (byte) '='; /** * Decodes URL encoded string including newly introduced JavaScript encoding with %uxxxx chars * * @param s encoded string * @param enc source encoding * @return decoded string or original if no decoding required * @throws UnsupportedEncodingException */ public static String decode(String s, String enc) throws UnsupportedEncodingException { if (enc == null || enc.length() == 0) { throw new UnsupportedEncodingException("decode: no source char encoding provided."); } boolean decoded = false; int l = s.length(); StringBuffer sb = new StringBuffer(l > 1024 ? l / 3 : l); int state = sText; int i = 0; int code = 0; char c; int pos = 0; int ofs = 0; byte[] buf = null; boolean processDig = false; while (i < l) { c = s.charAt(i); switch (c) { case '+': decoded = true; if (state == sText) sb.append(' '); else if (state == s2Dig) { sb.append(new String(buf, 0, pos + 1, enc)); state = sText; sb.append(' '); } else new IllegalArgumentException("decode: unexpected + at pos: " + i + ", of : " + s); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ofs = '0'; processDig = true; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': ofs = 'a' - 10; processDig = true; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': ofs = 'A' - 10; processDig = true; break; case '%': decoded = true; if (state == sText) { state = sEscape; if (buf == null) buf = new byte[(l - i) / 3]; pos = 0; } else if (state == s2Dig) { state = sEscape; pos++; } else new IllegalArgumentException("decode: unexpected escape % at pos: " + i + ", of : " + s); break; case 'u': if (state == sEscape) { if (pos > 0) { sb.append(new String(buf, 0, pos, enc)); pos = 0; } state = sU1; } else if (state == sText) { sb.append(c); } else if (state == s2Dig) { sb.append(new String(buf, 0, pos + 1, enc)); state = sText; sb.append(c); } else new IllegalArgumentException("decode: unexpected char in hex at pos: " + i + ", of : " + s); break; default: if (state == sText) sb.append(c); else if (state == s2Dig) { sb.append(new String(buf, 0, pos + 1, enc)); state = sText; sb.append(c); } else new IllegalArgumentException("decode: unexpected char in hex at pos: " + i + ", of : " + s); break; } i++; if (processDig) { if (state == sEscape) { code = c - ofs; state = s1Dig; } else if (state == s1Dig) { buf[pos] = (byte) (code * 16 + (c - ofs)); state = s2Dig; } else if (state == s2Dig) { // escape finished sb.append(new String(buf, 0, pos + 1, enc)); state = sText; sb.append(c); } else if (state == sU1) { code = c - ofs; state = sU2; } else if (state == sU2) { code = code * 16 + c - ofs; state = sU3; } else if (state == sU3) { code = code * 16 + c - ofs; state = sU4; } else if (state == sU4) { sb.append((char) (code * 16 + c - ofs)); state = sText; } else sb.append(c); processDig = false; } } if (state == s2Dig) sb.append(new String(buf, 0, pos + 1, enc)); return (decoded ? sb.toString() : s); } /** * Very low-level access to decoding ASCII characters in the form of a byte array. Does not support automatically gunzipping or any other "fancy" features. * * @param source The Base64 encoded data * @param off The offset of where to begin decoding * @param len The length of characters to decode * @return decoded data * @since 1.3 */ public static byte[] decode(byte[] source, int off, int len) { int len34 = len * 3 / 4; byte[] outBuff = new byte[len34]; // Upper limit on size of output int outBuffPosn = 0; byte[] b4 = new byte[4]; int b4Posn = 0; int i = 0; byte sbiCrop = 0; byte sbiDecode = 0; for (i = off; i < off + len; i++) { sbiCrop = (byte) (source[i] & 0x7f); // Only the low seven bits sbiDecode = DECODABET[sbiCrop]; if (sbiDecode >= WHITE_SPACE_ENC) // Whitesp ace,Eq ualssi gnor be // tter { if (sbiDecode >= EQUALS_SIGN_ENC) { b4[b4Posn++] = sbiCrop; if (b4Posn > 3) { outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn); b4Posn = 0; // If that was the equals sign, break out of 'for' loop if (sbiCrop == EQUALS_SIGN) break; } // end if: quartet built } // end if: equals sign or better } // end if: white space, equals sign or better else { System.err.println("Bad Base64 input character at " + i + ": " + source[i] + "(decimal)"); return null; } // end else: } // each input character byte[] out = new byte[outBuffPosn]; System.arraycopy(outBuff, 0, out, 0, outBuffPosn); return out; } /** * Decodes four bytes from array <var>source</var> and writes the resulting bytes (up to three of them) to <var>destination</var>. The source and * destination arrays can be manipulated anywhere along their length by specifying <var>srcOffset</var> and <var>destOffset</var>. This method does not * check to make sure your arrays are large enough to accomodate <var>srcOffset</var> + 4 for the <var>source</var> array or <var>destOffset</var> + 3 * for the <var>destination</var> array. This method returns the actual number of bytes that were converted from the Base64 encoding. * * @param source the array to convert * @param srcOffset the index where conversion begins * @param destination the array to hold the conversion * @param destOffset the index where output will be put * @return the number of decoded bytes converted * @since 1.3 */ private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset) { // Example: Dk== if (source[srcOffset + 2] == EQUALS_SIGN) { // Two ways to do the same thing. Don't know which way I like best. // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 // ) // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12); destination[destOffset] = (byte) (outBuff >>> 16); return 1; } // Example: DkL= else if (source[srcOffset + 3] == EQUALS_SIGN) { // Two ways to do the same thing. Don't know which way I like best. // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 // ) // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6); destination[destOffset] = (byte) (outBuff >>> 16); destination[destOffset + 1] = (byte) (outBuff >>> 8); return 2; } // Example: DkLE else { try { // Two ways to do the same thing. Don't know which way I like // best. // int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) // >>> 6 ) // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) | ((DECODABET[source[srcOffset + 3]] & 0xFF)); destination[destOffset] = (byte) (outBuff >> 16); destination[destOffset + 1] = (byte) (outBuff >> 8); destination[destOffset + 2] = (byte) (outBuff); return 3; } catch (Exception e) { System.out.println("" + source[srcOffset] + ": " + (DECODABET[source[srcOffset]])); System.out.println("" + source[srcOffset + 1] + ": " + (DECODABET[source[srcOffset + 1]])); System.out.println("" + source[srcOffset + 2] + ": " + (DECODABET[source[srcOffset + 2]])); System.out.println("" + source[srcOffset + 3] + ": " + (DECODABET[source[srcOffset + 3]])); return -1; } // e nd catch } } }