1 /*
   2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.messaging.saaj.util;
  27 
  28 
  29 // Cut & paste from tomcat
  30 
  31 /**
  32  * This class provides encode/decode for RFC 2045 Base64 as
  33  * defined by RFC 2045, N. Freed and N. Borenstein.
  34  * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
  35  * Part One: Format of Internet Message Bodies. Reference
  36  * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
  37  * This class is used by XML Schema binary format validation
  38  *
  39  * @author Jeffrey Rodriguez
  40  * @version
  41  */
  42 public final class Base64 {
  43 
  44 
  45     static private final int  BASELENGTH         = 255;
  46     static private final int  LOOKUPLENGTH       = 63;
  47     static private final int  TWENTYFOURBITGROUP = 24;
  48     static private final int  EIGHTBIT           = 8;
  49     static private final int  SIXTEENBIT         = 16;
  50     static private final int  FOURBYTE           = 4;
  51 
  52 
  53     static private final byte PAD               = ( byte ) '=';
  54     static private byte [] base64Alphabet       = new byte[BASELENGTH];
  55     static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
  56 
  57     static {
  58 
  59         for (int i = 0; i<BASELENGTH; i++ ) {
  60             base64Alphabet[i] = -1;
  61         }
  62         for ( int i = 'Z'; i >= 'A'; i-- ) {
  63             base64Alphabet[i] = (byte) (i-'A');
  64         }
  65         for ( int i = 'z'; i>= 'a'; i--) {
  66             base64Alphabet[i] = (byte) ( i-'a' + 26);
  67         }
  68 
  69         for ( int i = '9'; i >= '0'; i--) {
  70             base64Alphabet[i] = (byte) (i-'0' + 52);
  71         }
  72 
  73         base64Alphabet['+']  = 62;
  74         base64Alphabet['/']  = 63;
  75 
  76        for (int i = 0; i<=25; i++ )
  77             lookUpBase64Alphabet[i] = (byte) ('A'+i );
  78 
  79         for (int i = 26,  j = 0; i<=51; i++, j++ )
  80             lookUpBase64Alphabet[i] = (byte) ('a'+ j );
  81 
  82         for (int i = 52,  j = 0; i<=61; i++, j++ )
  83             lookUpBase64Alphabet[i] = (byte) ('0' + j );
  84 
  85     }
  86 
  87 
  88     static boolean isBase64( byte octect ) {
  89         //shall we ignore white space? JEFF??
  90         return(octect == PAD || base64Alphabet[octect] != -1 );
  91     }
  92 
  93 
  94     static boolean isArrayByteBase64( byte[] arrayOctect ) {
  95         int length = arrayOctect.length;
  96         if ( length == 0 )
  97             return false;
  98         for ( int i=0; i < length; i++ ) {
  99             if ( Base64.isBase64( arrayOctect[i] ) == false)
 100                 return false;
 101         }
 102         return true;
 103     }
 104 
 105     /**
 106      * Encodes hex octects into Base64
 107      *
 108      * @param binaryData Array containing binaryData
 109      * @return Encoded Base64 array
 110      */
 111     public static byte[] encode( byte[] binaryData ) {
 112         int      lengthDataBits    = binaryData.length*EIGHTBIT;
 113         int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
 114         int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
 115         byte     encodedData[]     = null;
 116 
 117 
 118         if ( fewerThan24bits != 0 ) //data not divisible by 24 bit
 119             encodedData = new byte[ (numberTriplets + 1 )*4  ];
 120         else // 16 or 8 bit
 121             encodedData = new byte[ numberTriplets*4 ];
 122 
 123         byte k=0, l=0, b1=0,b2=0,b3=0;
 124 
 125         int encodedIndex = 0;
 126         int dataIndex   = 0;
 127         int i           = 0;
 128         for ( i = 0; i<numberTriplets; i++ ) {
 129 
 130             dataIndex = i*3;
 131             b1 = binaryData[dataIndex];
 132             b2 = binaryData[dataIndex + 1];
 133             b3 = binaryData[dataIndex + 2];
 134 
 135             l  = (byte)(b2 & 0x0f);
 136             k  = (byte)(b1 & 0x03);
 137 
 138             encodedIndex = i*4;
 139             encodedData[encodedIndex]   = lookUpBase64Alphabet[ b1 >>2 ];
 140             encodedData[encodedIndex+1] = lookUpBase64Alphabet[(b2 >>4 ) |
 141 ( k<<4 )];
 142             encodedData[encodedIndex+2] = lookUpBase64Alphabet[ (l <<2 ) |
 143 ( b3>>6)];
 144             encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
 145         }
 146 
 147         // form integral number of 6-bit groups
 148         dataIndex    = i*3;
 149         encodedIndex = i*4;
 150         if (fewerThan24bits == EIGHTBIT ) {
 151             b1 = binaryData[dataIndex];
 152             k = (byte) ( b1 &0x03 );
 153             encodedData[encodedIndex]     = lookUpBase64Alphabet[ b1 >>2 ];
 154             encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
 155             encodedData[encodedIndex + 2] = PAD;
 156             encodedData[encodedIndex + 3] = PAD;
 157         } else if ( fewerThan24bits == SIXTEENBIT ) {
 158 
 159             b1 = binaryData[dataIndex];
 160             b2 = binaryData[dataIndex +1 ];
 161             l = ( byte ) ( b2 &0x0f );
 162             k = ( byte ) ( b1 &0x03 );
 163             encodedData[encodedIndex]     = lookUpBase64Alphabet[ b1 >>2 ];
 164             encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ (b2 >>4 )
 165 | ( k<<4 )];
 166             encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
 167             encodedData[encodedIndex + 3] = PAD;
 168         }
 169         return encodedData;
 170     }
 171 
 172 
 173     /**
 174      * Decodes Base64 data into octects
 175      *
 176      * @param binaryData Byte array containing Base64 data
 177      * @return Array containind decoded data.
 178      */
 179     public byte[] decode( byte[] base64Data ) {
 180         int      numberQuadruple    = base64Data.length/FOURBYTE;
 181         byte     decodedData[]      = null;
 182         byte     b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0;
 183 
 184         // Throw away anything not in base64Data
 185         // Adjust size
 186 
 187         int encodedIndex = 0;
 188         int dataIndex    = 0;
 189         decodedData      = new byte[ numberQuadruple*3 + 1 ];
 190 
 191         for (int i = 0; i<numberQuadruple; i++ ) {
 192             dataIndex = i*4;
 193             marker0   = base64Data[dataIndex +2];
 194             marker1   = base64Data[dataIndex +3];
 195 
 196             b1 = base64Alphabet[base64Data[dataIndex]];
 197             b2 = base64Alphabet[base64Data[dataIndex +1]];
 198 
 199             if ( marker0 != PAD && marker1 != PAD ) {     //No PAD e.g 3cQl
 200                 b3 = base64Alphabet[ marker0 ];
 201                 b4 = base64Alphabet[ marker1 ];
 202 
 203                 decodedData[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 ) ;
 204                 decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |(
 205 (b3>>2) & 0xf) );
 206                 decodedData[encodedIndex+2] = (byte)( b3<<6 | b4 );
 207             } else if ( marker0 == PAD ) {               //Two PAD e.g. 3c[Pad][Pad]
 208                 decodedData[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 ) ;
 209                 decodedData[encodedIndex+1] = (byte)((b2 & 0xf)<<4 );
 210                 decodedData[encodedIndex+2] = (byte) 0;
 211             } else if ( marker1 == PAD ) {              //One PAD e.g. 3cQ[Pad]
 212                 b3 = base64Alphabet[ marker0 ];
 213 
 214                 decodedData[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 );
 215                 decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |(
 216 (b3>>2) & 0xf) );
 217                 decodedData[encodedIndex+2] = (byte)( b3<<6);
 218             }
 219             encodedIndex += 3;
 220         }
 221         return decodedData;
 222 
 223     }
 224 
 225     static final int base64[]= {
 226         64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 227             64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 228             64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
 229             52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
 230             64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
 231             15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
 232             64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
 233             41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
 234             64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 235             64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 236             64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 237             64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 238             64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 239             64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 240             64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
 241             64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
 242     };
 243 
 244     public static String base64Decode( String orig ) {
 245         char chars[]=orig.toCharArray();
 246         StringBuilder sb=new StringBuilder();
 247         int i=0;
 248 
 249         int shift = 0;   // # of excess bits stored in accum
 250         int acc = 0;
 251 
 252         for (i=0; i<chars.length; i++) {
 253             int v = base64[ chars[i] & 0xFF ];
 254 
 255             if ( v >= 64 ) {
 256                 if( chars[i] != '=' )
 257                     System.out.println("Wrong char in base64: " + chars[i]);
 258             } else {
 259                 acc= ( acc << 6 ) | v;
 260                 shift += 6;
 261                 if ( shift >= 8 ) {
 262                     shift -= 8;
 263                     sb.append( (char) ((acc >> shift) & 0xff));
 264                 }
 265             }
 266         }
 267         return sb.toString();
 268     }
 269 
 270 
 271 }