1 //////////////////////license & copyright header/////////////////////////
2 // //
3 // Base64 - encode/decode data using the Base64 encoding scheme //
4 // //
5 // Copyright (c) 1998 by Kevin Kelley //
6 // //
7 // This library is free software; you can redistribute it and/or //
8 // modify it under the terms of the GNU Lesser General Public //
9 // License as published by the Free Software Foundation; either //
10 // version 2.1 of the License, or (at your option) any later version. //
11 // //
12 // This library is distributed in the hope that it will be useful, //
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
15 // GNU Lesser General Public License for more details. //
16 // //
17 // You should have received a copy of the GNU Lesser General Public //
18 // License along with this library; if not, write to the Free Software //
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA //
20 // 02111-1307, USA, or contact the author: //
21 // //
22 // Kevin Kelley <kelley@ruralnet.net> - 30718 Rd. 28, La Junta, CO, //
23 // 81050 USA. //
24 // //
25 ////////////////////end license & copyright header///////////////////////
26 package juju.reattore.util;
27
28 import java.io.*; // needed only for main() method.
29
30 /***
31 * Provides encoding of raw bytes to base64-encoded characters, and
32 * decoding of base64 characters to raw bytes.
33 *
34 * @author Kevin Kelley (kelley@ruralnet.net)
35 * @version 1.3
36 * @date 06 August 1998
37 * @modified 14 February 2000
38 * @modified 22 September 2000
39 */
40 public class Base64 {
41 //
42 // code characters for values 0..63
43 //
44 static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
45 .toCharArray();
46
47 //
48 // lookup table for converting base64 characters to value in range 0..63
49 //
50 static private byte[] codes = new byte[256];
51
52 static {
53 for (int i = 0; i < 256; i++)
54 codes[i] = -1;
55
56 for (int i = 'A'; i <= 'Z'; i++)
57 codes[i] = (byte) (i - 'A');
58
59 for (int i = 'a'; i <= 'z'; i++)
60 codes[i] = (byte) ((26 + i) - 'a');
61
62 for (int i = '0'; i <= '9'; i++)
63 codes[i] = (byte) ((52 + i) - '0');
64
65 codes['+'] = 62;
66 codes['/'] = 63;
67 }
68
69 /***
70 * returns an array of base64-encoded characters to represent the
71 * passed data array.
72 *
73 * @param data the array of bytes to encode
74 * @return base64-coded character array.
75 */
76 static public char[] encode(byte[] data) {
77 char[] out = new char[((data.length + 2) / 3) * 4];
78
79 //
80 // 3 bytes encode to 4 chars. Output is always an even
81 // multiple of 4 characters.
82 //
83 for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
84 boolean quad = false;
85 boolean trip = false;
86
87 int val = (0xFF & (int) data[i]);
88 val <<= 8;
89
90 if ((i + 1) < data.length) {
91 val |= (0xFF & (int) data[i + 1]);
92 trip = true;
93 }
94
95 val <<= 8;
96
97 if ((i + 2) < data.length) {
98 val |= (0xFF & (int) data[i + 2]);
99 quad = true;
100 }
101
102 out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
103 val >>= 6;
104 out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
105 val >>= 6;
106 out[index + 1] = alphabet[val & 0x3F];
107 val >>= 6;
108 out[index + 0] = alphabet[val & 0x3F];
109 }
110
111 return out;
112 }
113
114 /***
115 * Decodes a BASE-64 encoded stream to recover the original
116 * data. White space before and after will be trimmed away,
117 * but no other manipulation of the input will be performed.
118 *
119 * As of version 1.2 this method will properly handle input
120 * containing junk characters (newlines and the like) rather
121 * than throwing an error. It does this by pre-parsing the
122 * input and generating from that a count of VALID input
123 * characters.
124 **/
125 static public byte[] decode(char[] data) {
126 // as our input could contain non-BASE64 data (newlines,
127 // whitespace of any sort, whatever) we must first adjust
128 // our count of USABLE data so that...
129 // (a) we don't misallocate the output array, and
130 // (b) think that we miscalculated our data length
131 // just because of extraneous throw-away junk
132 int tempLen = data.length;
133
134 for (int ix = 0; ix < data.length; ix++) {
135 if ((data[ix] > 255) || (codes[data[ix]] < 0)) {
136 --tempLen; // ignore non-valid chars and padding
137 }
138 }
139
140 // calculate required length:
141 // -- 3 bytes for every 4 valid base64 chars
142 // -- plus 2 bytes if there are 3 extra base64 chars,
143 // or plus 1 byte if there are 2 extra.
144 int len = (tempLen / 4) * 3;
145
146 if ((tempLen % 4) == 3) {
147 len += 2;
148 }
149
150 if ((tempLen % 4) == 2) {
151 len += 1;
152 }
153
154 byte[] out = new byte[len];
155
156 int shift = 0; // # of excess bits stored in accum
157 int accum = 0; // excess bits
158 int index = 0;
159
160 // we now go through the entire array (NOT using the 'tempLen' value)
161 for (int ix = 0; ix < data.length; ix++) {
162 int value = (data[ix] > 255) ? (-1) : codes[data[ix]];
163
164 if (value >= 0) // skip over non-code
165 {
166 accum <<= 6; // bits shift up by 6 each time thru
167 shift += 6; // loop, with new bits being put in
168 accum |= value; // at the bottom.
169
170 if (shift >= 8) // whenever there are 8 or more shifted in,
171 {
172 shift -= 8; // write them out (from the top, leaving any
173 out[index++] = (byte) ((accum >> shift) & 0xff);
174 }
175 }
176
177 // we will also have skipped processing a padding null byte ('=') here;
178 // these are used ONLY for padding to an even length and do not legally
179 // occur as encoded data. for this reason we can ignore the fact that
180 // no index++ operation occurs in that special case: the out[] array is
181 // initialized to all-zero bytes to start with and that works to our
182 // advantage in this combination.
183 }
184
185 // if there is STILL something wrong we just have to throw up now!
186 if (index != out.length) {
187 throw new Error("Miscalculated data length (wrote " + index + " instead of "
188 + out.length + ")");
189 }
190
191 return out;
192 }
193
194 ///////////////////////////////////////////////////
195 // remainder (main method and helper functions) is
196 // for testing purposes only, feel free to clip it.
197 ///////////////////////////////////////////////////
198 public static void main(String[] args) {
199 boolean decode = false;
200
201 if (args.length == 0) {
202 System.out.println("usage: java Base64 [-d[ecode]] filename");
203 System.exit(0);
204 }
205
206 for (int i = 0; i < args.length; i++) {
207 if ("-decode".equalsIgnoreCase(args[i])) {
208 decode = true;
209 }
210 else if ("-d".equalsIgnoreCase(args[i])) {
211 decode = true;
212 }
213 }
214
215 String filename = args[args.length - 1];
216 File file = new File(filename);
217
218 if (!file.exists()) {
219 System.out.println("Error: file '" + filename + "' doesn't exist!");
220 System.exit(0);
221 }
222
223 if (decode) {
224 char[] encoded = readChars(file);
225 byte[] decoded = decode(encoded);
226 writeBytes(file, decoded);
227 }
228 else {
229 byte[] decoded = readBytes(file);
230 char[] encoded = encode(decoded);
231 writeChars(file, encoded);
232 }
233 }
234
235 private static byte[] readBytes(File file) {
236 ByteArrayOutputStream baos = new ByteArrayOutputStream();
237
238 try {
239 InputStream fis = new FileInputStream(file);
240 InputStream is = new BufferedInputStream(fis);
241 int count = 0;
242 byte[] buf = new byte[16384];
243
244 while ((count = is.read(buf)) != -1) {
245 if (count > 0) {
246 baos.write(buf, 0, count);
247 }
248 }
249
250 is.close();
251 }
252 catch (Exception e) {
253 e.printStackTrace();
254 }
255
256 return baos.toByteArray();
257 }
258
259 private static char[] readChars(File file) {
260 CharArrayWriter caw = new CharArrayWriter();
261
262 try {
263 Reader fr = new FileReader(file);
264 Reader in = new BufferedReader(fr);
265 int count = 0;
266 char[] buf = new char[16384];
267
268 while ((count = in.read(buf)) != -1) {
269 if (count > 0) {
270 caw.write(buf, 0, count);
271 }
272 }
273
274 in.close();
275 }
276 catch (Exception e) {
277 e.printStackTrace();
278 }
279
280 return caw.toCharArray();
281 }
282
283 private static void writeBytes(File file, byte[] data) {
284 try {
285 OutputStream fos = new FileOutputStream(file);
286 OutputStream os = new BufferedOutputStream(fos);
287 os.write(data);
288 os.close();
289 }
290 catch (Exception e) {
291 e.printStackTrace();
292 }
293 }
294
295 private static void writeChars(File file, char[] data) {
296 try {
297 Writer fos = new FileWriter(file);
298 Writer os = new BufferedWriter(fos);
299 os.write(data);
300 os.close();
301 }
302 catch (Exception e) {
303 e.printStackTrace();
304 }
305 }
306
307 ///////////////////////////////////////////////////
308 // end of test code.
309 ///////////////////////////////////////////////////
310 }
This page was automatically generated by Maven