Home » xmlbeans-2.5.0-src » org.apache.xmlbeans.impl » util » [javadoc | source]

    1   /*   Copyright 2004 The Apache Software Foundation
    2    *
    3    *   Licensed under the Apache License, Version 2.0 (the "License");
    4    *   you may not use this file except in compliance with the License.
    5    *   You may obtain a copy of the License at
    6    *
    7    *       http://www.apache.org/licenses/LICENSE-2.0
    8    *
    9    *   Unless required by applicable law or agreed to in writing, software
   10    *   distributed under the License is distributed on an "AS IS" BASIS,
   11    *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12    *   See the License for the specific language governing permissions and
   13    *  limitations under the License.
   14    */
   15   
   16   package org.apache.xmlbeans.impl.util;
   17   
   18   import java.io.UnsupportedEncodingException;
   19   /**
   20    * This class provides encode/decode for RFC 2045 Base64 as
   21    * defined by RFC 2045, N. Freed and N. Borenstein.
   22    * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
   23    * Part One: Format of Internet Message Bodies. Reference
   24    * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
   25    * This class is used by XML Schema binary format validation
   26    *
   27    * This implementation does not encode/decode streaming
   28    * data. You need the data that you will encode/decode
   29    * already on a byte arrray.
   30    *
   31    * @author Jeffrey Rodriguez
   32    * @author Sandy Gao
   33    * @version $Id: Base64.java 111285 2004-12-08 16:54:26Z cezar $
   34    */
   35   public final class  Base64 {
   36   
   37       static private final int  BASELENGTH         = 255;
   38       static private final int  LOOKUPLENGTH       = 64;
   39       static private final int  TWENTYFOURBITGROUP = 24;
   40       static private final int  EIGHTBIT           = 8;
   41       static private final int  SIXTEENBIT         = 16;
   42       //static private final int  SIXBIT             = 6;
   43       static private final int  FOURBYTE           = 4;
   44       static private final int  SIGN               = -128;
   45       static private final byte PAD                = ( byte ) '=';
   46       static private final boolean fDebug          = false;
   47       static private byte [] base64Alphabet        = new byte[BASELENGTH];
   48       static private byte [] lookUpBase64Alphabet  = new byte[LOOKUPLENGTH];
   49   
   50       static {
   51   
   52           for (int i = 0; i<BASELENGTH; i++) {
   53               base64Alphabet[i] = -1;
   54           }
   55           for (int i = 'Z'; i >= 'A'; i--) {
   56               base64Alphabet[i] = (byte) (i-'A');
   57           }
   58           for (int i = 'z'; i>= 'a'; i--) {
   59               base64Alphabet[i] = (byte) ( i-'a' + 26);
   60           }
   61   
   62           for (int i = '9'; i >= '0'; i--) {
   63               base64Alphabet[i] = (byte) (i-'0' + 52);
   64           }
   65   
   66           base64Alphabet['+']  = 62;
   67           base64Alphabet['/']  = 63;
   68   
   69           for (int i = 0; i<=25; i++)
   70               lookUpBase64Alphabet[i] = (byte) ('A'+i );
   71   
   72           for (int i = 26,  j = 0; i<=51; i++, j++)
   73               lookUpBase64Alphabet[i] = (byte) ('a'+ j );
   74   
   75           for (int i = 52,  j = 0; i<=61; i++, j++)
   76               lookUpBase64Alphabet[i] = (byte) ('0' + j );
   77           lookUpBase64Alphabet[62] = (byte) '+';
   78           lookUpBase64Alphabet[63] = (byte) '/';
   79   
   80       }
   81   
   82       protected static boolean isWhiteSpace(byte octect) {
   83           return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
   84       }
   85   
   86       protected static boolean isPad(byte octect) {
   87           return (octect == PAD);
   88       }
   89   
   90       protected static boolean isData(byte octect) {
   91           return (base64Alphabet[octect] != -1);
   92       }
   93   
   94       protected static boolean isBase64(byte octect) {
   95           return (isWhiteSpace(octect) || isPad(octect) || isData(octect));
   96       }
   97   
   98       /**
   99        * Encodes hex octects into Base64
  100        *
  101        * @param binaryData Array containing binaryData
  102        * @return Encoded Base64 array
  103        */
  104       public static byte[] encode(byte[] binaryData) {
  105   
  106           if (binaryData == null)
  107               return null;
  108   
  109           int      lengthDataBits    = binaryData.length*EIGHTBIT;
  110           int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
  111           int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
  112           byte     encodedData[]     = null;
  113   
  114           if (fewerThan24bits != 0) //data not divisible by 24 bit
  115               encodedData = new byte[ (numberTriplets + 1 )*4  ];
  116           else // 16 or 8 bit
  117               encodedData = new byte[ numberTriplets*4 ];
  118   
  119           byte k=0, l=0, b1=0,b2=0,b3=0;
  120   
  121           int encodedIndex = 0;
  122           int dataIndex   = 0;
  123           int i           = 0;
  124           if (fDebug) {
  125               System.out.println("number of triplets = " + numberTriplets );
  126           }
  127           for (i = 0; i<numberTriplets; i++) {
  128   
  129               dataIndex = i*3;
  130               b1 = binaryData[dataIndex];
  131               b2 = binaryData[dataIndex + 1];
  132               b3 = binaryData[dataIndex + 2];
  133   
  134               if (fDebug) {
  135                   System.out.println( "b1= " + b1 +", b2= " + b2 + ", b3= " + b3 );
  136               }
  137   
  138               l  = (byte)(b2 & 0x0f);
  139               k  = (byte)(b1 & 0x03);
  140   
  141               encodedIndex = i*4;
  142               byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
  143   
  144               byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
  145               byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
  146   
  147               encodedData[encodedIndex]   = lookUpBase64Alphabet[ val1 ];
  148               if (fDebug) {
  149                   System.out.println( "val2 = " + val2 );
  150                   System.out.println( "k4   = " + (k<<4));
  151                   System.out.println( "vak  = " + (val2 | (k<<4)));
  152               }
  153   
  154               encodedData[encodedIndex+1] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
  155               encodedData[encodedIndex+2] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
  156               encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
  157           }
  158   
  159           // form integral number of 6-bit groups
  160           dataIndex    = i*3;
  161           encodedIndex = i*4;
  162           if (fewerThan24bits == EIGHTBIT) {
  163               b1 = binaryData[dataIndex];
  164               k = (byte) ( b1 &0x03 );
  165               if (fDebug) {
  166                   System.out.println("b1=" + b1);
  167                   System.out.println("b1<<2 = " + (b1>>2) );
  168               }
  169               byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
  170               encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
  171               encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
  172               encodedData[encodedIndex + 2] = PAD;
  173               encodedData[encodedIndex + 3] = PAD;
  174           } else if (fewerThan24bits == SIXTEENBIT) {
  175   
  176               b1 = binaryData[dataIndex];
  177               b2 = binaryData[dataIndex +1 ];
  178               l = ( byte ) ( b2 &0x0f );
  179               k = ( byte ) ( b1 &0x03 );
  180   
  181               byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
  182               byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
  183   
  184               encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
  185               encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
  186               encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
  187               encodedData[encodedIndex + 3] = PAD;
  188           }
  189   
  190           return encodedData;
  191       }
  192   
  193       /**
  194        * Decodes Base64 data into octects
  195        *
  196        * @param base64Data Byte array containing Base64 data
  197        * @return Array containind decoded data.
  198        */
  199       public static byte[] decode(byte[] base64Data) {
  200   
  201           if (base64Data == null)
  202               return null;
  203   
  204           // remove white spaces
  205           base64Data = removeWhiteSpace(base64Data);
  206   
  207           if (base64Data.length%FOURBYTE != 0) {
  208               return null;//should be divisible by four
  209           }
  210   
  211           int      numberQuadruple    = (base64Data.length/FOURBYTE );
  212   
  213           if (numberQuadruple == 0)
  214               return new byte[0];
  215   
  216           byte     decodedData[]      = null;
  217           byte     b1=0,b2=0,b3=0, b4=0;//, marker0=0, marker1=0;
  218           byte     d1=0,d2=0,d3=0,d4=0;
  219   
  220           // Throw away anything not in normalizedBase64Data
  221           // Adjust size
  222           int i = 0;
  223           int encodedIndex = 0;
  224           int dataIndex    = 0;
  225           decodedData      = new byte[ (numberQuadruple)*3];
  226   
  227           for (; i<numberQuadruple-1; i++) {
  228   
  229               if (!isData( (d1 = base64Data[dataIndex++]) )||
  230                   !isData( (d2 = base64Data[dataIndex++]) )||
  231                   !isData( (d3 = base64Data[dataIndex++]) )||
  232                   !isData( (d4 = base64Data[dataIndex++]) ))
  233                   return null;//if found "no data" just return null
  234   
  235               b1 = base64Alphabet[d1];
  236               b2 = base64Alphabet[d2];
  237               b3 = base64Alphabet[d3];
  238               b4 = base64Alphabet[d4];
  239   
  240               decodedData[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 ) ;
  241               decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
  242               decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
  243           }
  244   
  245           if (!isData( (d1 = base64Data[dataIndex++]) ) ||
  246               !isData( (d2 = base64Data[dataIndex++]) )) {
  247               return null;//if found "no data" just return null
  248           }
  249   
  250           b1 = base64Alphabet[d1];
  251           b2 = base64Alphabet[d2];
  252   
  253           d3 = base64Data[dataIndex++];
  254           d4 = base64Data[dataIndex++];
  255           if (!isData( (d3 ) ) ||
  256               !isData( (d4 ) )) {//Check if they are PAD characters
  257               if (isPad( d3 ) && isPad( d4)) {               //Two PAD e.g. 3c[Pad][Pad]
  258                   if ((b2 & 0xf) != 0)//last 4 bits should be zero
  259                       return null;
  260                   byte[] tmp = new byte[ i*3 + 1 ];
  261                   System.arraycopy( decodedData, 0, tmp, 0, i*3 );
  262                   tmp[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 ) ;
  263                   return tmp;
  264               } else if (!isPad( d3) && isPad(d4)) {               //One PAD  e.g. 3cQ[Pad]
  265                   b3 = base64Alphabet[ d3 ];
  266                   if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
  267                       return null;
  268                   byte[] tmp = new byte[ i*3 + 2 ];
  269                   System.arraycopy( decodedData, 0, tmp, 0, i*3 );
  270                   tmp[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 );
  271                   tmp[encodedIndex]   = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
  272                   return tmp;
  273               } else {
  274                   return null;//an error  like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
  275               }
  276           } else { //No PAD e.g 3cQl
  277               b3 = base64Alphabet[ d3 ];
  278               b4 = base64Alphabet[ d4 ];
  279               decodedData[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 ) ;
  280               decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
  281               decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
  282   
  283           }
  284   
  285           return decodedData;
  286       }
  287   
  288   //    /**
  289   //     * Decodes Base64 data into octects
  290   //     *
  291   //     * @param base64Data String containing Base64 data
  292   //     * @return string containing decoded data.
  293   //     */
  294   //    public static String decode(String base64Data) {
  295   //        if (base64Data == null)
  296   //            return null;
  297   //
  298   //        byte[] decoded = null;
  299   //        try {
  300   //            decoded = decode(base64Data.getBytes("utf-8"));
  301   //        }
  302   //        catch(UnsupportedEncodingException e) {
  303   //        }
  304   //        finally {
  305   //            return decoded == null ? null : new String(decoded);
  306   //        }
  307   //    }
  308   //
  309   //    /**
  310   //     * Encodes octects (using utf-8) into Base64 data
  311   //     *
  312   //     * @param binaryData String containing Hex data
  313   //     * @return string containing decoded data.
  314   //     */
  315   //    public static String encode(String binaryData) {
  316   //        if (binaryData == null)
  317   //            return null;
  318   //
  319   //        byte[] encoded = null;
  320   //         try {
  321   //          encoded = encode(binaryData.getBytes("utf-8"));
  322   //        }
  323   //        catch(UnsupportedEncodingException e) {}
  324   //        finally {
  325   //            return encoded == null ? null : new String(encoded);
  326   //        }
  327   //    }
  328   
  329       /**
  330        * remove WhiteSpace from MIME containing encoded Base64 data.
  331        *
  332        * @param data  the byte array of base64 data (with WS)
  333        * @return      the byte array of base64 data (without WS)
  334        */
  335       protected static byte[] removeWhiteSpace(byte[] data) {
  336           if (data == null)
  337               return null;
  338   
  339           // count characters that's not whitespace
  340           int newSize = 0;
  341           int len = data.length;
  342           for (int i = 0; i < len; i++) {
  343               if (!isWhiteSpace(data[i]))
  344                   newSize++;
  345           }
  346   
  347           // if no whitespace, just return the input array
  348           if (newSize == len)
  349               return data;
  350   
  351           // create the array to return
  352           byte[] newArray = new byte[newSize];
  353   
  354           int j = 0;
  355           for (int i = 0; i < len; i++) {
  356               if (!isWhiteSpace(data[i]))
  357                   newArray[j++] = data[i];
  358           }
  359           return newArray;
  360       }
  361   }

Home » xmlbeans-2.5.0-src » org.apache.xmlbeans.impl » util » [javadoc | source]