FileDocCategorySizeDatePackage
Base64.javaAPI DocApache Tomcat 6.0.1410329Fri Jul 20 04:20:36 BST 2007org.apache.catalina.util

Base64

public final class Base64 extends Object
This class provides encode/decode for RFC 2045 Base64 as defined by RFC 2045, N. Freed and N. Borenstein. RFC 2045: Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies. Reference 1996
author
Jeffrey Rodriguez
version
$Id: Base64.java 467222 2006-10-24 03:17:11Z markt $

Fields Summary
private static final int
BASELENGTH
private static final int
LOOKUPLENGTH
private static final int
TWENTYFOURBITGROUP
private static final int
EIGHTBIT
private static final int
SIXTEENBIT
private static final int
SIXBIT
private static final int
FOURBYTE
private static final int
SIGN
private static final byte
PAD
private static byte[]
base64Alphabet
private static byte[]
lookUpBase64Alphabet
Constructors Summary
Methods Summary
public static voiddecode(org.apache.tomcat.util.buf.ByteChunk base64DataBC, org.apache.tomcat.util.buf.CharChunk decodedDataCC)
Decodes Base64 data into octects

param
base64DataBC Byte array containing Base64 data
param
decodedDataCC The decoded data chars

        int start = base64DataBC.getStart();
        int end = base64DataBC.getEnd();
        byte[] base64Data = base64DataBC.getBuffer();
        
        decodedDataCC.recycle();
        
        // handle the edge case, so we don't have to worry about it later
        if(end - start == 0) { return; }

        int      numberQuadruple    = (end - start)/FOURBYTE;
        byte     b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0;

        // Throw away anything not in base64Data

        int encodedIndex = 0;
        int dataIndex = start;
        char[] decodedData = null;
        
        {
            // this sizes the output array properly - rlw
            int lastData = end - start;
            // ignore the '=' padding
            while (base64Data[start+lastData-1] == PAD)
            {
                if (--lastData == 0)
                {
                    return;
                }
            }
            decodedDataCC.allocate(lastData - numberQuadruple, -1);
            decodedDataCC.setEnd(lastData - numberQuadruple);
            decodedData = decodedDataCC.getBuffer();
        }

        for (int i = 0; i < numberQuadruple; i++)
        {
            dataIndex = start + i * 4;
            marker0   = base64Data[dataIndex + 2];
            marker1   = base64Data[dataIndex + 3];

            b1 = base64Alphabet[base64Data[dataIndex]];
            b2 = base64Alphabet[base64Data[dataIndex +1]];

            if (marker0 != PAD && marker1 != PAD)
            {
                //No PAD e.g 3cQl
                b3 = base64Alphabet[ marker0 ];
                b4 = base64Alphabet[ marker1 ];

                decodedData[encodedIndex]   = (char) ((  b1 <<2 | b2>>4 ) & 0xff);
                decodedData[encodedIndex + 1] =
                    (char) ((((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ) & 0xff);
                decodedData[encodedIndex + 2] = (char) (( b3<<6 | b4 ) & 0xff);
            }
            else if (marker0 == PAD)
            {
                //Two PAD e.g. 3c[Pad][Pad]
                decodedData[encodedIndex]   = (char) ((  b1 <<2 | b2>>4 ) & 0xff);
            }
            else if (marker1 == PAD)
            {
                //One PAD e.g. 3cQ[Pad]
                b3 = base64Alphabet[ marker0 ];

                decodedData[encodedIndex]   = (char) ((  b1 <<2 | b2>>4 ) & 0xff);
                decodedData[encodedIndex + 1] =
                    (char) ((((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) ) & 0xff);
            }
            encodedIndex += 3;
        }
    
public static byte[]encode(byte[] binaryData)
Encodes hex octects into Base64.

param
binaryData Array containing binary data to encode.
return
Base64-encoded data.

        int      lengthDataBits    = binaryData.length*EIGHTBIT;
        int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
        int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
        byte     encodedData[]     = null;


        if (fewerThan24bits != 0)
        {
            //data not divisible by 24 bit
            encodedData = new byte[ (numberTriplets + 1 ) * 4 ];
        }
        else
        {
            // 16 or 8 bit
            encodedData = new byte[ numberTriplets * 4 ];
        }

        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;

        int encodedIndex = 0;
        int dataIndex   = 0;
        int i           = 0;
        //log.debug("number of triplets = " + numberTriplets);
        for ( i = 0; i<numberTriplets; i++ )
        {
            dataIndex = i*3;
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            b3 = binaryData[dataIndex + 2];

            //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);

            l  = (byte)(b2 & 0x0f);
            k  = (byte)(b1 & 0x03);

            encodedIndex = i * 4;
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
            byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);

            encodedData[encodedIndex]   = lookUpBase64Alphabet[ val1 ];
            //log.debug( "val2 = " + val2 );
            //log.debug( "k4   = " + (k<<4) );
            //log.debug(  "vak  = " + (val2 | (k<<4)) );
            encodedData[encodedIndex+1] =
                lookUpBase64Alphabet[ val2 | ( k<<4 )];
            encodedData[encodedIndex+2] =
                lookUpBase64Alphabet[ (l <<2 ) | val3 ];
            encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
        }

        // form integral number of 6-bit groups
        dataIndex    = i*3;
        encodedIndex = i*4;
        if (fewerThan24bits == EIGHTBIT )
        {
            b1 = binaryData[dataIndex];
            k = (byte) ( b1 &0x03 );
            //log.debug("b1=" + b1);
            //log.debug("b1<<2 = " + (b1>>2) );
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
            encodedData[encodedIndex + 2] = PAD;
            encodedData[encodedIndex + 3] = PAD;
        }
        else if (fewerThan24bits == SIXTEENBIT)
        {

            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex +1 ];
            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);

            byte val1 = ((b1 & SIGN) == 0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            byte val2 = ((b2 & SIGN) == 0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);

            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex + 1] =
                lookUpBase64Alphabet[ val2 | ( k<<4 )];
            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
            encodedData[encodedIndex + 3] = PAD;
        }

        return encodedData;
    
public static booleanisArrayByteBase64(byte[] arrayOctect)

        int length = arrayOctect.length;
        if (length == 0)
        {
            // shouldn't a 0 length array be valid base64 data?
            // return false;
            return true;
        }
        for (int i=0; i < length; i++)
        {
            if ( !Base64.isBase64(arrayOctect[i]) )
                return false;
        }
        return true;
    
public static booleanisBase64(java.lang.String isValidString)

    //static private final Log log = LogSource.getInstance("org.apache.commons.util.Base64");

    
    
        for (int i = 0; i < BASELENGTH; i++ )
        {
            base64Alphabet[i] = -1;
        }
        for (int i = 'Z"; i >= 'A"; i--)
        {
            base64Alphabet[i] = (byte) (i - 'A");
        }
        for (int i = 'z"; i>= 'a"; i--)
        {
            base64Alphabet[i] = (byte) (i - 'a" + 26);
        }
        for (int i = '9"; i >= '0"; i--)
        {
            base64Alphabet[i] = (byte) (i - '0" + 52);
        }

        base64Alphabet['+"]  = 62;
        base64Alphabet['/"]  = 63;

        for (int i = 0; i <= 25; i++ )
            lookUpBase64Alphabet[i] = (byte) ('A" + i);

        for (int i = 26,  j = 0; i <= 51; i++, j++ )
            lookUpBase64Alphabet[i] = (byte) ('a"+ j);

        for (int i = 52,  j = 0; i <= 61; i++, j++ )
            lookUpBase64Alphabet[i] = (byte) ('0" + j);

        lookUpBase64Alphabet[62] = (byte) '+";
        lookUpBase64Alphabet[63] = (byte) '/";
    
        return isArrayByteBase64(isValidString.getBytes());
    
public static booleanisBase64(byte octect)

        //shall we ignore white space? JEFF??
        return (octect == PAD || base64Alphabet[octect] != -1);