private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset, int options )
    {
        byte[] DECODABET = getDecodabet( options );

        // 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){
                LOG.info(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset     ] ]  ) );
                LOG.info(""+source[srcOffset+1]+  ": " + ( DECODABET[ source[ srcOffset + 1 ] ]  ) );
                LOG.info(""+source[srcOffset+2]+  ": " + ( DECODABET[ source[ srcOffset + 2 ] ]  ) );
                LOG.info(""+source[srcOffset+3]+  ": " + ( DECODABET[ source[ srcOffset + 3 ] ]  ) );
                return -1;
            }   // end catch
        }
    }
private static int decode4to3 ( byte [ ] source , int srcOffset , byte [ ] destination , int destOffset , int options ) { byte [ ] DECODABET = getDecodabet ( options ) ; if ( source [ srcOffset + 2 ] == EQUALS_SIGN ) { int outBuff = ( ( DECODABET [ source [ srcOffset ] ] & 0xFF ) << 18 ) | ( ( DECODABET [ source [ srcOffset + 1 ] ] & 0xFF ) << 12 ) ; destination [ destOffset ] = ( byte ) ( outBuff > > > 16 ) ; return 1 ; } else if ( source [ srcOffset + 3 ] == EQUALS_SIGN ) { 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 ; } else { try { 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 ) { LOG . info ( "" + source [ srcOffset ] + ": " + ( DECODABET [ source [ srcOffset ] ] ) ) ; LOG . info ( "" + source [ srcOffset + 1 ] + ": " + ( DECODABET [ source [ srcOffset + 1 ] ] ) ) ; LOG . info ( "" + source [ srcOffset + 2 ] + ": " + ( DECODABET [ source [ srcOffset + 2 ] ] ) ) ; LOG . info ( "" + source [ srcOffset + 3 ] + ": " + ( DECODABET [ source [ srcOffset + 3 ] ] ) ) ; return - 1 ; } } }
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.
<p>This is the lowest level of the decoding methods with
all possible parameters.</p>


@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
@param options alphabet type is pulled from this (standard, url-safe, ordered)
@return the number of decoded bytes converted
@since 1.3