1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xerces" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, International
  53. * Business Machines, Inc., http://www.apache.org. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package com.sun.org.apache.xerces.internal.impl.dv.util;
  58. /**
  59. * This class provides encode/decode for RFC 2045 Base64 as
  60. * defined by RFC 2045, N. Freed and N. Borenstein.
  61. * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
  62. * Part One: Format of Internet Message Bodies. Reference
  63. * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
  64. * This class is used by XML Schema binary format validation
  65. *
  66. * This implementation does not encode/decode streaming
  67. * data. You need the data that you will encode/decode
  68. * already on a byte arrray.
  69. *
  70. * @author Jeffrey Rodriguez
  71. * @author Sandy Gao
  72. * @version $Id: Base64.java,v 1.8 2003/05/08 20:11:55 elena Exp $
  73. */
  74. public final class Base64 {
  75. static private final int BASELENGTH = 255;
  76. static private final int LOOKUPLENGTH = 64;
  77. static private final int TWENTYFOURBITGROUP = 24;
  78. static private final int EIGHTBIT = 8;
  79. static private final int SIXTEENBIT = 16;
  80. static private final int SIXBIT = 6;
  81. static private final int FOURBYTE = 4;
  82. static private final int SIGN = -128;
  83. static private final char PAD = '=';
  84. static private final boolean fDebug = false;
  85. static final private byte [] base64Alphabet = new byte[BASELENGTH];
  86. static final private char [] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
  87. static {
  88. for (int i = 0; i<BASELENGTH; i++) {
  89. base64Alphabet[i] = -1;
  90. }
  91. for (int i = 'Z'; i >= 'A'; i--) {
  92. base64Alphabet[i] = (byte) (i-'A');
  93. }
  94. for (int i = 'z'; i>= 'a'; i--) {
  95. base64Alphabet[i] = (byte) ( i-'a' + 26);
  96. }
  97. for (int i = '9'; i >= '0'; i--) {
  98. base64Alphabet[i] = (byte) (i-'0' + 52);
  99. }
  100. base64Alphabet['+'] = 62;
  101. base64Alphabet['/'] = 63;
  102. for (int i = 0; i<=25; i++)
  103. lookUpBase64Alphabet[i] = (char)('A'+i);
  104. for (int i = 26, j = 0; i<=51; i++, j++)
  105. lookUpBase64Alphabet[i] = (char)('a'+ j);
  106. for (int i = 52, j = 0; i<=61; i++, j++)
  107. lookUpBase64Alphabet[i] = (char)('0' + j);
  108. lookUpBase64Alphabet[62] = (char)'+';
  109. lookUpBase64Alphabet[63] = (char)'/';
  110. }
  111. protected static boolean isWhiteSpace(char octect) {
  112. return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
  113. }
  114. protected static boolean isPad(char octect) {
  115. return (octect == PAD);
  116. }
  117. protected static boolean isData(char octect) {
  118. return (base64Alphabet[octect] != -1);
  119. }
  120. protected static boolean isBase64(char octect) {
  121. return (isWhiteSpace(octect) || isPad(octect) || isData(octect));
  122. }
  123. /**
  124. * Encodes hex octects into Base64
  125. *
  126. * @param binaryData Array containing binaryData
  127. * @return Encoded Base64 array
  128. */
  129. public static String encode(byte[] binaryData) {
  130. if (binaryData == null)
  131. return null;
  132. int lengthDataBits = binaryData.length*EIGHTBIT;
  133. if (lengthDataBits == 0) {
  134. return "";
  135. }
  136. int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP;
  137. int numberTriplets = lengthDataBitsTWENTYFOURBITGROUP;
  138. int numberQuartet = fewerThan24bits != 0 ? numberTriplets+1 : numberTriplets;
  139. int numberLines = (numberQuartet-1)/19+1;
  140. char encodedData[] = null;
  141. encodedData = new char[numberQuartet*4+numberLines];
  142. byte k=0, l=0, b1=0,b2=0,b3=0;
  143. int encodedIndex = 0;
  144. int dataIndex = 0;
  145. int i = 0;
  146. if (fDebug) {
  147. System.out.println("number of triplets = " + numberTriplets );
  148. }
  149. for (int line = 0; line < numberLines-1; line++) {
  150. for (int quartet = 0; quartet < 19; quartet++) {
  151. b1 = binaryData[dataIndex++];
  152. b2 = binaryData[dataIndex++];
  153. b3 = binaryData[dataIndex++];
  154. if (fDebug) {
  155. System.out.println( "b1= " + b1 +", b2= " + b2 + ", b3= " + b3 );
  156. }
  157. l = (byte)(b2 & 0x0f);
  158. k = (byte)(b1 & 0x03);
  159. byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
  160. byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
  161. byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
  162. if (fDebug) {
  163. System.out.println( "val2 = " + val2 );
  164. System.out.println( "k4 = " + (k<<4));
  165. System.out.println( "vak = " + (val2 | (k<<4)));
  166. }
  167. encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
  168. encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
  169. encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
  170. encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];
  171. i++;
  172. }
  173. encodedData[encodedIndex++] = 0xa;
  174. }
  175. for (; i<numberTriplets; i++) {
  176. b1 = binaryData[dataIndex++];
  177. b2 = binaryData[dataIndex++];
  178. b3 = binaryData[dataIndex++];
  179. if (fDebug) {
  180. System.out.println( "b1= " + b1 +", b2= " + b2 + ", b3= " + b3 );
  181. }
  182. l = (byte)(b2 & 0x0f);
  183. k = (byte)(b1 & 0x03);
  184. byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
  185. byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
  186. byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
  187. if (fDebug) {
  188. System.out.println( "val2 = " + val2 );
  189. System.out.println( "k4 = " + (k<<4));
  190. System.out.println( "vak = " + (val2 | (k<<4)));
  191. }
  192. encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
  193. encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
  194. encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
  195. encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];
  196. }
  197. // form integral number of 6-bit groups
  198. if (fewerThan24bits == EIGHTBIT) {
  199. b1 = binaryData[dataIndex];
  200. k = (byte) ( b1 &0x03 );
  201. if (fDebug) {
  202. System.out.println("b1=" + b1);
  203. System.out.println("b1<<2 = " + (b1>>2) );
  204. }
  205. byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
  206. encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
  207. encodedData[encodedIndex++] = lookUpBase64Alphabet[ k<<4 ];
  208. encodedData[encodedIndex++] = PAD;
  209. encodedData[encodedIndex++] = PAD;
  210. } else if (fewerThan24bits == SIXTEENBIT) {
  211. b1 = binaryData[dataIndex];
  212. b2 = binaryData[dataIndex +1 ];
  213. l = ( byte ) ( b2 &0x0f );
  214. k = ( byte ) ( b1 &0x03 );
  215. byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
  216. byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
  217. encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
  218. encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
  219. encodedData[encodedIndex++] = lookUpBase64Alphabet[ l<<2 ];
  220. encodedData[encodedIndex++] = PAD;
  221. }
  222. encodedData[encodedIndex] = 0xa;
  223. return new String(encodedData);
  224. }
  225. /**
  226. * Decodes Base64 data into octects
  227. *
  228. * @param binaryData Byte array containing Base64 data
  229. * @return Array containind decoded data.
  230. */
  231. public static byte[] decode(String encoded) {
  232. if (encoded == null)
  233. return null;
  234. char[] base64Data = encoded.toCharArray();
  235. // remove white spaces
  236. int len = removeWhiteSpace(base64Data);
  237. if (len%FOURBYTE != 0) {
  238. return null;//should be divisible by four
  239. }
  240. int numberQuadruple = (lenFOURBYTE );
  241. if (numberQuadruple == 0)
  242. return new byte[0];
  243. byte decodedData[] = null;
  244. byte b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0;
  245. char d1=0,d2=0,d3=0,d4=0;
  246. int i = 0;
  247. int encodedIndex = 0;
  248. int dataIndex = 0;
  249. decodedData = new byte[ (numberQuadruple)*3];
  250. for (; i<numberQuadruple-1; i++) {
  251. if (!isData( (d1 = base64Data[dataIndex++]) )||
  252. !isData( (d2 = base64Data[dataIndex++]) )||
  253. !isData( (d3 = base64Data[dataIndex++]) )||
  254. !isData( (d4 = base64Data[dataIndex++]) ))
  255. return null;//if found "no data" just return null
  256. b1 = base64Alphabet[d1];
  257. b2 = base64Alphabet[d2];
  258. b3 = base64Alphabet[d3];
  259. b4 = base64Alphabet[d4];
  260. decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ;
  261. decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
  262. decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
  263. }
  264. if (!isData( (d1 = base64Data[dataIndex++]) ) ||
  265. !isData( (d2 = base64Data[dataIndex++]) )) {
  266. return null;//if found "no data" just return null
  267. }
  268. b1 = base64Alphabet[d1];
  269. b2 = base64Alphabet[d2];
  270. d3 = base64Data[dataIndex++];
  271. d4 = base64Data[dataIndex++];
  272. if (!isData( (d3 ) ) ||
  273. !isData( (d4 ) )) {//Check if they are PAD characters
  274. if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad]
  275. if ((b2 & 0xf) != 0)//last 4 bits should be zero
  276. return null;
  277. byte[] tmp = new byte[ i*3 + 1 ];
  278. System.arraycopy( decodedData, 0, tmp, 0, i*3 );
  279. tmp[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ;
  280. return tmp;
  281. } else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
  282. b3 = base64Alphabet[ d3 ];
  283. if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
  284. return null;
  285. byte[] tmp = new byte[ i*3 + 2 ];
  286. System.arraycopy( decodedData, 0, tmp, 0, i*3 );
  287. tmp[encodedIndex++] = (byte)( b1 <<2 | b2>>4 );
  288. tmp[encodedIndex] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
  289. return tmp;
  290. } else {
  291. return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
  292. }
  293. } else { //No PAD e.g 3cQl
  294. b3 = base64Alphabet[ d3 ];
  295. b4 = base64Alphabet[ d4 ];
  296. decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ;
  297. decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
  298. decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
  299. }
  300. return decodedData;
  301. }
  302. /**
  303. * remove WhiteSpace from MIME containing encoded Base64 data.
  304. *
  305. * @param data the byte array of base64 data (with WS)
  306. * @return the new length
  307. */
  308. protected static int removeWhiteSpace(char[] data) {
  309. if (data == null)
  310. return 0;
  311. // count characters that's not whitespace
  312. int newSize = 0;
  313. int len = data.length;
  314. for (int i = 0; i < len; i++) {
  315. if (!isWhiteSpace(data[i]))
  316. data[newSize++] = data[i];
  317. }
  318. return newSize;
  319. }
  320. }