Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

Base64.java

00001 /*
00002  * The Apache Software License, Version 1.1
00003  *
00004  *
00005  * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
00006  * reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  *
00012  * 1. Redistributions of source code must retain the above copyright
00013  *    notice, this list of conditions and the following disclaimer.
00014  *
00015  * 2. Redistributions in binary form must reproduce the above copyright
00016  *    notice, this list of conditions and the following disclaimer in
00017  *    the documentation and/or other materials provided with the
00018  *    distribution.
00019  *
00020  * 3. The end-user documentation included with the redistribution,
00021  *    if any, must include the following acknowledgment:
00022  *       "This product includes software developed by the
00023  *        Apache Software Foundation (http://www.apache.org/)."
00024  *    Alternately, this acknowledgment may appear in the software itself,
00025  *    if and wherever such third-party acknowledgments normally appear.
00026  *
00027  * 4. The names "Xerces" and "Apache Software Foundation" must
00028  *    not be used to endorse or promote products derived from this
00029  *    software without prior written permission. For written
00030  *    permission, please contact apache@apache.org.
00031  *
00032  * 5. Products derived from this software may not be called "Apache",
00033  *    nor may "Apache" appear in their name, without prior written
00034  *    permission of the Apache Software Foundation.
00035  *
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00039  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
00040  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00041  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00042  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
00043  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00044  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00045  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00046  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00047  * SUCH DAMAGE.
00048  * ====================================================================
00049  *
00050  * This software consists of voluntary contributions made by many
00051  * individuals on behalf of the Apache Software Foundation and was
00052  * originally based on software copyright (c) 1999, International
00053  * Business Machines, Inc., http://www.apache.org.  For more
00054  * information on the Apache Software Foundation, please see
00055  * <http://www.apache.org/>.
00056  */
00057 
00058 package org.objectweb.cjdbc.common.stream.encoding;
00059 
00060 /**
00061  * This class provides encode/decode for RFC 2045 Base64 as defined by RFC 2045,
00062  * N. Freed and N. Borenstein. RFC 2045: Multipurpose Internet Mail Extensions
00063  * (MIME) Part One: Format of Internet Message Bodies. Reference 1996 Available
00064  * at: http://www.ietf.org/rfc/rfc2045.txt This class is used by XML Schema
00065  * binary format validation This implementation does not encode/decode streaming
00066  * data. You need the data that you will encode/decode already on a byte arrray.
00067  * 
00068  * @author Jeffrey Rodriguez
00069  * @author Sandy Gao
00070  * @version $Id: Base64.java,v 1.3 2005/04/11 18:14:55 cecchet Exp $
00071  */
00072 public final class Base64
00073 {
00074 
00075   static private final int     BASELENGTH           = 255;
00076   static private final int     LOOKUPLENGTH         = 64;
00077   static private final int     TWENTYFOURBITGROUP   = 24;
00078   static private final int     EIGHTBIT             = 8;
00079   static private final int     SIXTEENBIT           = 16;
00080   static private final int     FOURBYTE             = 4;
00081   static private final int     SIGN                 = -128;
00082   static private final char    PAD                  = '=';
00083   static private final boolean fDebug               = false;
00084   static final private byte[]  base64Alphabet       = new byte[BASELENGTH];
00085   static final private char[]  lookUpBase64Alphabet = new char[LOOKUPLENGTH];
00086 
00087   static
00088   {
00089 
00090     for (int i = 0; i < BASELENGTH; i++)
00091     {
00092       base64Alphabet[i] = -1;
00093     }
00094     for (int i = 'Z'; i >= 'A'; i--)
00095     {
00096       base64Alphabet[i] = (byte) (i - 'A');
00097     }
00098     for (int i = 'z'; i >= 'a'; i--)
00099     {
00100       base64Alphabet[i] = (byte) (i - 'a' + 26);
00101     }
00102 
00103     for (int i = '9'; i >= '0'; i--)
00104     {
00105       base64Alphabet[i] = (byte) (i - '0' + 52);
00106     }
00107 
00108     base64Alphabet['+'] = 62;
00109     base64Alphabet['/'] = 63;
00110 
00111     for (int i = 0; i <= 25; i++)
00112       lookUpBase64Alphabet[i] = (char) ('A' + i);
00113 
00114     for (int i = 26, j = 0; i <= 51; i++, j++)
00115       lookUpBase64Alphabet[i] = (char) ('a' + j);
00116 
00117     for (int i = 52, j = 0; i <= 61; i++, j++)
00118       lookUpBase64Alphabet[i] = (char) ('0' + j);
00119     lookUpBase64Alphabet[62] = '+';
00120     lookUpBase64Alphabet[63] = '/';
00121   }
00122 
00123   protected static boolean isWhiteSpace(char octect)
00124   {
00125     return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
00126   }
00127 
00128   protected static boolean isPad(char octect)
00129   {
00130     return (octect == PAD);
00131   }
00132 
00133   protected static boolean isData(char octect)
00134   {
00135     return (base64Alphabet[octect] != -1);
00136   }
00137 
00138   protected static boolean isBase64(char octect)
00139   {
00140     return (isWhiteSpace(octect) || isPad(octect) || isData(octect));
00141   }
00142 
00143   /**
00144    * Encodes hex octects into Base64
00145    * 
00146    * @param binaryData Array containing binaryData
00147    * @return Encoded Base64 array
00148    */
00149   public static String encode(byte[] binaryData)
00150   {
00151 
00152     if (binaryData == null)
00153       return null;
00154 
00155     int lengthDataBits = binaryData.length * EIGHTBIT;
00156     if (lengthDataBits == 0)
00157     {
00158       return "";
00159     }
00160 
00161     int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
00162     int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
00163     int numberQuartet = fewerThan24bits != 0
00164         ? numberTriplets + 1
00165         : numberTriplets;
00166     int numberLines = (numberQuartet - 1) / 19 + 1;
00167     char encodedData[] = null;
00168 
00169     encodedData = new char[numberQuartet * 4 + numberLines];
00170 
00171     byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
00172 
00173     int encodedIndex = 0;
00174     int dataIndex = 0;
00175     int i = 0;
00176     if (fDebug)
00177     {
00178       System.out.println("number of triplets = " + numberTriplets);
00179     }
00180 
00181     for (int line = 0; line < numberLines - 1; line++)
00182     {
00183       for (int quartet = 0; quartet < 19; quartet++)
00184       {
00185         b1 = binaryData[dataIndex++];
00186         b2 = binaryData[dataIndex++];
00187         b3 = binaryData[dataIndex++];
00188 
00189         if (fDebug)
00190         {
00191           System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
00192         }
00193 
00194         l = (byte) (b2 & 0x0f);
00195         k = (byte) (b1 & 0x03);
00196 
00197         byte val1 = ((b1 & SIGN) == 0)
00198             ? (byte) (b1 >> 2)
00199             : (byte) ((b1) >> 2 ^ 0xc0);
00200 
00201         byte val2 = ((b2 & SIGN) == 0)
00202             ? (byte) (b2 >> 4)
00203             : (byte) ((b2) >> 4 ^ 0xf0);
00204         byte val3 = ((b3 & SIGN) == 0)
00205             ? (byte) (b3 >> 6)
00206             : (byte) ((b3) >> 6 ^ 0xfc);
00207 
00208         if (fDebug)
00209         {
00210           System.out.println("val2 = " + val2);
00211           System.out.println("k4   = " + (k << 4));
00212           System.out.println("vak  = " + (val2 | (k << 4)));
00213         }
00214 
00215         encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
00216         encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
00217         encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
00218         encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
00219 
00220         i++;
00221       }
00222       encodedData[encodedIndex++] = 0xa;
00223     }
00224 
00225     for (; i < numberTriplets; i++)
00226     {
00227       b1 = binaryData[dataIndex++];
00228       b2 = binaryData[dataIndex++];
00229       b3 = binaryData[dataIndex++];
00230 
00231       if (fDebug)
00232       {
00233         System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
00234       }
00235 
00236       l = (byte) (b2 & 0x0f);
00237       k = (byte) (b1 & 0x03);
00238 
00239       byte val1 = ((b1 & SIGN) == 0)
00240           ? (byte) (b1 >> 2)
00241           : (byte) ((b1) >> 2 ^ 0xc0);
00242 
00243       byte val2 = ((b2 & SIGN) == 0)
00244           ? (byte) (b2 >> 4)
00245           : (byte) ((b2) >> 4 ^ 0xf0);
00246       byte val3 = ((b3 & SIGN) == 0)
00247           ? (byte) (b3 >> 6)
00248           : (byte) ((b3) >> 6 ^ 0xfc);
00249 
00250       if (fDebug)
00251       {
00252         System.out.println("val2 = " + val2);
00253         System.out.println("k4   = " + (k << 4));
00254         System.out.println("vak  = " + (val2 | (k << 4)));
00255       }
00256 
00257       encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
00258       encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
00259       encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
00260       encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
00261     }
00262 
00263     // form integral number of 6-bit groups
00264     if (fewerThan24bits == EIGHTBIT)
00265     {
00266       b1 = binaryData[dataIndex];
00267       k = (byte) (b1 & 0x03);
00268       if (fDebug)
00269       {
00270         System.out.println("b1=" + b1);
00271         System.out.println("b1<<2 = " + (b1 >> 2));
00272       }
00273       byte val1 = ((b1 & SIGN) == 0)
00274           ? (byte) (b1 >> 2)
00275           : (byte) ((b1) >> 2 ^ 0xc0);
00276       encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
00277       encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
00278       encodedData[encodedIndex++] = PAD;
00279       encodedData[encodedIndex++] = PAD;
00280     }
00281     else if (fewerThan24bits == SIXTEENBIT)
00282     {
00283       b1 = binaryData[dataIndex];
00284       b2 = binaryData[dataIndex + 1];
00285       l = (byte) (b2 & 0x0f);
00286       k = (byte) (b1 & 0x03);
00287 
00288       byte val1 = ((b1 & SIGN) == 0)
00289           ? (byte) (b1 >> 2)
00290           : (byte) ((b1) >> 2 ^ 0xc0);
00291       byte val2 = ((b2 & SIGN) == 0)
00292           ? (byte) (b2 >> 4)
00293           : (byte) ((b2) >> 4 ^ 0xf0);
00294 
00295       encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
00296       encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
00297       encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
00298       encodedData[encodedIndex++] = PAD;
00299     }
00300 
00301     encodedData[encodedIndex] = 0xa;
00302 
00303     return new String(encodedData);
00304   }
00305 
00306   /**
00307    * Decodes Base64 data into octects
00308    * 
00309    * @param encoded String encoded in Base64
00310    * @return Byte array containing decoded data.
00311    */
00312   public static byte[] decode(String encoded)
00313   {
00314 
00315     if (encoded == null)
00316       return null;
00317 
00318     char[] base64Data = encoded.toCharArray();
00319     // remove white spaces
00320     int len = removeWhiteSpace(base64Data);
00321 
00322     if (len % FOURBYTE != 0)
00323     {
00324       return null;//should be divisible by four
00325     }
00326 
00327     int numberQuadruple = (len / FOURBYTE);
00328 
00329     if (numberQuadruple == 0)
00330       return new byte[0];
00331 
00332     byte decodedData[] = null;
00333     byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
00334     char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
00335 
00336     int i = 0;
00337     int encodedIndex = 0;
00338     int dataIndex = 0;
00339     decodedData = new byte[(numberQuadruple) * 3];
00340 
00341     for (; i < numberQuadruple - 1; i++)
00342     {
00343 
00344       if (!isData((d1 = base64Data[dataIndex++]))
00345           || !isData((d2 = base64Data[dataIndex++]))
00346           || !isData((d3 = base64Data[dataIndex++]))
00347           || !isData((d4 = base64Data[dataIndex++])))
00348         return null;//if found "no data" just return null
00349 
00350       b1 = base64Alphabet[d1];
00351       b2 = base64Alphabet[d2];
00352       b3 = base64Alphabet[d3];
00353       b4 = base64Alphabet[d4];
00354 
00355       decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
00356       decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
00357       decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
00358     }
00359 
00360     if (!isData((d1 = base64Data[dataIndex++]))
00361         || !isData((d2 = base64Data[dataIndex++])))
00362     {
00363       return null;//if found "no data" just return null
00364     }
00365 
00366     b1 = base64Alphabet[d1];
00367     b2 = base64Alphabet[d2];
00368 
00369     d3 = base64Data[dataIndex++];
00370     d4 = base64Data[dataIndex++];
00371     if (!isData((d3)) || !isData((d4)))
00372     {//Check if they are PAD characters
00373       if (isPad(d3) && isPad(d4))
00374       { //Two PAD e.g. 3c[Pad][Pad]
00375         if ((b2 & 0xf) != 0)//last 4 bits should be zero
00376           return null;
00377         byte[] tmp = new byte[i * 3 + 1];
00378         System.arraycopy(decodedData, 0, tmp, 0, i * 3);
00379         tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
00380         return tmp;
00381       }
00382       else if (!isPad(d3) && isPad(d4))
00383       { //One PAD e.g. 3cQ[Pad]
00384         b3 = base64Alphabet[d3];
00385         if ((b3 & 0x3) != 0)//last 2 bits should be zero
00386           return null;
00387         byte[] tmp = new byte[i * 3 + 2];
00388         System.arraycopy(decodedData, 0, tmp, 0, i * 3);
00389         tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
00390         tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
00391         return tmp;
00392       }
00393       else
00394       {
00395         return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X
00396         // is non data
00397       }
00398     }
00399     else
00400     { //No PAD e.g 3cQl
00401       b3 = base64Alphabet[d3];
00402       b4 = base64Alphabet[d4];
00403       decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
00404       decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
00405       decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
00406 
00407     }
00408 
00409     return decodedData;
00410   }
00411 
00412   /**
00413    * remove WhiteSpace from MIME containing encoded Base64 data.
00414    * 
00415    * @param data the byte array of base64 data (with WS)
00416    * @return the new length
00417    */
00418   protected static int removeWhiteSpace(char[] data)
00419   {
00420     if (data == null)
00421       return 0;
00422 
00423     // count characters that's not whitespace
00424     int newSize = 0;
00425     int len = data.length;
00426     for (int i = 0; i < len; i++)
00427     {
00428       if (!isWhiteSpace(data[i]))
00429         data[newSize++] = data[i];
00430     }
00431     return newSize;
00432   }
00433 }

Generated on Mon Apr 11 22:01:29 2005 for C-JDBC by  doxygen 1.3.9.1