Java Byte Array Decode decode(byte[] source, int off, int len)

Here you can find the source of decode(byte[] source, int off, int len)

Description

Very low-level access to decoding ASCII characters in the form of a byte array.

License

Open Source License

Parameter

Parameter Description
source The Base64 encoded data
off The offset of where to begin decoding
len The length of characters to decode

Return

decoded data

Declaration

public static byte[] decode(byte[] source, int off, int len) 

Method Source Code

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

Related

  1. decode(byte[] bytes)
  2. decode(byte[] bytes)
  3. decode(byte[] bytes)
  4. decode(byte[] msgToDecode)
  5. decode(byte[] source)
  6. decode(byte[] src, String charset)
  7. decode(Byte[] wrap)
  8. decode(final byte[] source, final int off, final int len)
  9. decode(String encoding, byte[] bytes)