Java Base64 Decode base64Decode(String _s, String _enc)

Here you can find the source of base64Decode(String _s, String _enc)

Description

base 64 decoding

License

Open Source License

Parameter

Parameter Description
encoded string
encoding used to get string bytes

Return

result of encoding, or null if encoding invalid or string null, or string is invalid base 64 encoding

Declaration

public final static String base64Decode(String _s, String _enc) 

Method Source Code

//package com.java2s;

import java.io.UnsupportedEncodingException;

public class Main {
    public final static String ISO_8859_1 = "ISO-8859-1";
    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;
    /**//from ww  w  . ja va 2 s .  c  o  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) '=';

    /**
     * base 64 decoding
     *
     * @param encoded  string
     * @param encoding used to get string bytes
     * @return result of encoding, or null if encoding invalid or string null, or string is invalid base 64 encoding
     */
    public final static String base64Decode(String _s, String _enc) {
        if (_s == null)
            return null;
        if (_enc == null)
            _enc = ISO_8859_1;
        try {
            return new String(decode64(_s), _enc);
        } catch (UnsupportedEncodingException uee) {
        }
        return null;
    }

    /**
     * Decodes data from Base64 notation, automatically detecting gzip-compressed data and decompressing it.
     *
     * @param s the string to decode
     * @return the decoded data
     * @since 1.4
     */
    public static byte[] decode64(String s) {
        byte[] bytes;
        try {
            bytes = s.getBytes(ISO_8859_1);
        } // end try
        catch (java.io.UnsupportedEncodingException uee) {
            bytes = s.getBytes();
        } // end catch
          // </change>

        // Decode
        bytes = decode(bytes, 0, bytes.length);

        // Check to see if it's gzip-compressed
        // GZIP Magic Two-Byte Number: 0x8b1f (35615)
        if (bytes != null && bytes.length >= 4) {

            int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
            if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head) {
                java.io.ByteArrayInputStream bais = null;
                java.util.zip.GZIPInputStream gzis = null;
                java.io.ByteArrayOutputStream baos = null;
                byte[] buffer = new byte[2048];
                int length = 0;

                try {
                    baos = new java.io.ByteArrayOutputStream();
                    bais = new java.io.ByteArrayInputStream(bytes);
                    gzis = new java.util.zip.GZIPInputStream(bais);

                    while ((length = gzis.read(buffer)) >= 0) {
                        baos.write(buffer, 0, length);
                    } // end while: reading input

                    // No error? Get new bytes.
                    bytes = baos.toByteArray();

                } // end try
                catch (java.io.IOException e) {
                    // Just return originally-decoded bytes
                } // end catch
                finally {
                    try {
                        baos.close();
                    } catch (Exception e) {
                    }
                    try {
                        gzis.close();
                    } catch (Exception e) {
                    }
                    try {
                        bais.close();
                    } catch (Exception e) {
                    }
                } // end finally

            } // end if: gzipped
        } // end if: bytes.length >= 2

        return bytes;
    }

    /**
     * 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
        }
    }
}

Related

  1. base64Decode(byte[] data)
  2. base64Decode(byte[] textBytes)
  3. base64Decode(char[] a_data)
  4. base64Decode(final String data)
  5. base64Decode(final String s)
  6. base64Decode(String b64)
  7. base64Decode(String base64Str)
  8. base64Decode(String data)
  9. base64Decode(String input)