View Javadoc
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