View Javadoc

1   package org.catacomb.util;
2   
3   /*
4   
5   * $Id: Base64.java,v 1.2 2010-05-31 11:01:45 rcc Exp $
6   *
7   * Copyright (c) 2000-2002 by Russell Gold
8   *
9   * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
10  * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
12  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all copies or substantial portions
15  * of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23   */
24  
25  /**
26   * A utility class to convert to and from base 64 encoding.
27   *
28   * @author <a href="mailto:russgold@httpunit.org">Russell Gold</a>
29   **/
30  public class Base64 {
31  
32      final static String encodingChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
33  
34  
35      /**
36       * Returns the base 64 encoded equivalent of a supplied string.
37       * @param source the string to encode
38       */
39      public static String encode(String source) {
40          char[] sourceBytes = getPaddedBytes(source);
41          int numGroups = (sourceBytes.length + 2) / 3;
42          char[] targetBytes = new char[4];
43          char[] target = new char[ 4 * numGroups ];
44  
45          for (int group = 0; group < numGroups; group++) {
46              convert3To4(sourceBytes, group*3, targetBytes);
47              for (int i = 0; i < targetBytes.length; i++) {
48                  target[ i + 4*group ] = encodingChar.charAt(targetBytes[i]);
49              }
50          }
51  
52          int numPadBytes = sourceBytes.length - source.length();
53  
54          for (int i = target.length-numPadBytes; i < target.length; i++) target[i] = '=';
55          return new String(target);
56      }
57  
58  
59      private static char[] getPaddedBytes(String source) {
60          char[] converted = source.toCharArray();
61          int requiredLength = 3 * ((converted.length+2) /3);
62          char[] result = new char[ requiredLength ];
63          System.arraycopy(converted, 0, result, 0, converted.length);
64          return result;
65      }
66  
67  
68      private static void convert3To4(char[] source, int sourceIndex, char[] target) {
69          target[0] = (char)(source[ sourceIndex ] >>> 2);
70          target[1] = (char)(((source[ sourceIndex   ] & 0x03) << 4) | (source[ sourceIndex+1 ] >>> 4));
71          target[2] = (char)(((source[ sourceIndex+1 ] & 0x0f) << 2) | (source[ sourceIndex+2 ] >>> 6));
72          target[3] = (char)(source[ sourceIndex+2 ] & 0x3f);
73      }
74  
75  
76      /**
77       * Returns the plaintext equivalent of a base 64-encoded string.
78       * @param source a base 64 string (which must have a multiple of 4 characters)
79       */
80      public static String decode(String source) {
81          if (source.length()%4 != 0) throw new RuntimeException("valid Base64 codes have a multiple of 4 characters");
82          int numGroups = source.length() / 4;
83          int numExtraBytes = source.endsWith("==") ? 2 : (source.endsWith("=") ? 1 : 0);
84          byte[] targetBytes = new byte[ 3*numGroups ];
85          byte[] sourceBytes = new byte[4];
86          for (int group = 0; group < numGroups; group++) {
87              for (int i = 0; i < sourceBytes.length; i++) {
88                  sourceBytes[i] = (byte) Math.max(0, encodingChar.indexOf(source.charAt(4*group+i)));
89              }
90              convert4To3(sourceBytes, targetBytes, group*3);
91          }
92          return new String(targetBytes, 0, targetBytes.length - numExtraBytes);
93      }
94  
95  
96      private static void convert4To3(byte[] source, byte[] target, int targetIndex) {
97          target[ targetIndex  ]  = (byte)((source[0] << 2) | (source[1] >>> 4));
98          target[ targetIndex+1 ] = (byte)(((source[1] & 0x0f) << 4) | (source[2] >>> 2));
99          target[ targetIndex+2 ] = (byte)(((source[2] & 0x03) << 6) | (source[3]));
100     }
101 
102 }