View Javadoc

1   package name.angoca.zemucan.tools;
2   
3   /**
4    * A Base64 Encoder/Decoder.
5    * <p>
6    * This class is used to encode and decode data in Base64 format as described in
7    * RFC 1521.
8    * <p>
9    * This is "Open Source" software and released under the <a
10   * href="http://www.gnu.org/licenses/lgpl.html">GNU/LGPL</a> license.<br>
11   * It is provided "as is" without warranty of any kind.<br>
12   * Copyright 2003: Christian d'Heureuse, Inventec Informatik AG, Switzerland.<br>
13   * Home page: <a href="http://www.source-code.biz">www.source-code.biz</a><br>
14   * <p>
15   * Version history:<br>
16   * 2003-07-22 Christian d'Heureuse (chdh): Module created.<br>
17   * 2005-08-11 chdh: Lincense changed from GPL to LGPL.<br>
18   * 2006-11-21 chdh:<br>
19   * &nbsp; Method encode(String) renamed to encodeString(String).<br>
20   * &nbsp; Method decode(String) renamed to decodeString(String).<br>
21   * &nbsp; New method encode(byte[],int) added.<br>
22   * &nbsp; New method decode(String) added.<br>
23   *
24   * @author Christian d'Heureuse
25   * @version 1.0.0 2010-05-13
26   */
27  public final class Base64 {
28      /**
29       * Mapping table from 6-bit nibbles to Base64 characters.
30       */
31      private static char[] map1 = new char[64];
32  
33      /**
34       * Mapping table from Base64 characters to 6-bit nibbles.
35       */
36      private static byte[] map2 = new byte[128];
37      static {
38          int i = 0;
39          for (char c = 'A'; c <= 'Z'; c += 1) {
40              Base64.map1[i] = c;
41              i += 1;
42          }
43          for (char c = 'a'; c <= 'z'; c += 1) {
44              Base64.map1[i] = c;
45              i += 1;
46          }
47          for (char c = '0'; c <= '9'; c += 1) {
48              Base64.map1[i] = c;
49              i += 1;
50          }
51          Base64.map1[i] = '+';
52          i += 1;
53          Base64.map1[i] = '/';
54          i += 1;
55      }
56  
57      static {
58          for (int i = 0; i < Base64.map2.length; i += 1) {
59              Base64.map2[i] = -1;
60          }
61          for (int i = 0; i < 64; i += 1) {
62              Base64.map2[Base64.map1[i]] = (byte) i;
63          }
64      }
65  
66      /**
67       * Decodes a byte array from Base64 format. No blanks or line breaks are
68       * allowed within the Base64 encoded data.
69       *
70       * @param in
71       *            a character array containing the Base64 encoded data.
72       * @return An array containing the decoded data bytes.
73       * @throws IllegalArgumentException
74       *             if the input is not valid Base64 encoded data.
75       */
76      public static byte[] decode(final char[] in) {
77          int iLen = in.length;
78          if (iLen % 4 != 0) {
79              throw new IllegalArgumentException(
80                      "Length of Base64 encoded input string is not a multiple of 4.");
81          }
82          while ((iLen > 0) && (in[iLen - 1] == '=')) {
83              iLen -= 1;
84          }
85          final int oLen = (iLen * 3) / 4;
86          final byte[] out = new byte[oLen];
87          int ip = 0;
88          int op = 0;
89          while (ip < iLen) {
90              final int i0 = in[ip];
91              ip += 1;
92              final int i1 = in[ip];
93              ip += 1;
94              final int i2 = (ip < iLen) ? in[ip] : 'A';
95              ip += 1;
96              final int i3 = (ip < iLen) ? in[ip] : 'A';
97              ip += 1;
98              if ((i0 > 127) || (i1 > 127) || (i2 > 127) || (i3 > 127)) {
99                  throw new IllegalArgumentException(
100                         "Illegal character in Base64 encoded data.");
101             }
102             final int b0 = Base64.map2[i0];
103             final int b1 = Base64.map2[i1];
104             final int b2 = Base64.map2[i2];
105             final int b3 = Base64.map2[i3];
106             if ((b0 < 0) || (b1 < 0) || (b2 < 0) || (b3 < 0)) {
107                 throw new IllegalArgumentException(
108                         "Illegal character in Base64 encoded data.");
109             }
110             final int o0 = (b0 << 2) | (b1 >>> 4);
111             final int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
112             final int o2 = ((b2 & 3) << 6) | b3;
113             out[op] = (byte) o0;
114             op += 1;
115             if (op < oLen) {
116                 out[op] = (byte) o1;
117                 op += 1;
118             }
119             if (op < oLen) {
120                 out[op] = (byte) o2;
121                 op += 1;
122             }
123         }
124         return out;
125     }
126 
127     /**
128      * Decodes a byte array from Base64 format.
129      *
130      * @param s
131      *            a Base64 String to be decoded.
132      * @return An array containing the decoded data bytes.
133      * @throws IllegalArgumentException
134      *             if the input is not valid Base64 encoded data.
135      */
136     public static byte[] decode(final String s) {
137         return Base64.decode(s.toCharArray());
138     }
139 
140     /**
141      * Decodes a string from Base64 format.
142      *
143      * @param s
144      *            a Base64 String to be decoded.
145      * @return A String containing the decoded data.
146      * @throws IllegalArgumentException
147      *             if the input is not valid Base64 encoded data.
148      */
149     public static String decodeString(final String s) {
150         return new String(Base64.decode(s));
151     }
152 
153     /**
154      * Encodes a byte array into Base64 format. No blanks or line breaks are
155      * inserted.
156      *
157      * @param in
158      *            an array containing the data bytes to be encoded.
159      * @return A character array with the Base64 encoded data.
160      */
161     public static char[] encode(final byte[] in) {
162         return Base64.encode(in, in.length);
163     }
164 
165     /**
166      * Encodes a byte array into Base64 format. No blanks or line breaks are
167      * inserted.
168      *
169      * @param in
170      *            an array containing the data bytes to be encoded.
171      * @param iLen
172      *            number of bytes to process in <code>in</code>.
173      * @return A character array with the Base64 encoded data.
174      */
175     public static char[] encode(final byte[] in, final int iLen) {
176         // output length without padding
177         final int oDataLen = (iLen * 4 + 2) / 3;
178         // output length including padding
179         final int oLen = ((iLen + 2) / 3) * 4;
180         final char[] out = new char[oLen];
181         int ip = 0;
182         int op = 0;
183         while (ip < iLen) {
184             final int i0 = in[ip] & 0xff;
185             ip += 1;
186             final int i1 = (ip < iLen) ? in[ip] & 0xff : 0;
187             ip += 1;
188             final int i2 = (ip < iLen) ? in[ip] & 0xff : 0;
189             ip += 1;
190             final int o0 = i0 >>> 2;
191             final int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
192             final int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
193             final int o3 = i2 & 0x3F;
194             out[op] = Base64.map1[o0];
195             op += 1;
196             out[op] = Base64.map1[o1];
197             ip += 1;
198             out[op] = (op < oDataLen) ? Base64.map1[o2] : '=';
199             op += 1;
200             out[op] = (op < oDataLen) ? Base64.map1[o3] : '=';
201             op += 1;
202         }
203         return out;
204     }
205 
206     /**
207      * Encodes a string into Base64 format. No blanks or line breaks are
208      * inserted.
209      *
210      * @param s
211      *            a String to be encoded.
212      * @return A String with the Base64 encoded data.
213      */
214     public static String encodeString(final String s) {
215         return new String(Base64.encode(s.getBytes()));
216     }
217 
218     /**
219      * Default constructor.
220      */
221     private Base64() {
222         // Nothing.
223     }
224 }