001 /* 002 * Java Base64 - A pure Java library for reading and writing Base64 003 * encoded streams. 004 * 005 * Copyright (C) 2007-2009 Carlo Pelliccia (www.sauronsoftware.it) 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU Lesser General Public License version 009 * 2.1, as published by the Free Software Foundation. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License version 2.1 along with this program. 018 * If not, see <http://www.gnu.org/licenses/>. 019 */ 020 package it.sauronsoftware.base64; 021 022 import java.io.ByteArrayInputStream; 023 import java.io.ByteArrayOutputStream; 024 import java.io.File; 025 import java.io.FileInputStream; 026 import java.io.FileOutputStream; 027 import java.io.IOException; 028 import java.io.InputStream; 029 import java.io.OutputStream; 030 import java.io.UnsupportedEncodingException; 031 032 /** 033 * <p> 034 * Base64 encoding and decoding utility methods, both for binary and textual 035 * informations. 036 * </p> 037 * 038 * @author Carlo Pelliccia 039 * @since 1.1 040 * @version 1.3 041 */ 042 public class Base64 { 043 044 /** 045 * <p> 046 * Encodes a string. 047 * </p> 048 * <p> 049 * Before the string is encoded in Base64, it is converted in a binary 050 * sequence using the system default charset. 051 * </p> 052 * 053 * @param str 054 * The source string. 055 * @return The encoded string. 056 * @throws RuntimeException 057 * If an unexpected error occurs. 058 */ 059 public static String encode(String str) throws RuntimeException { 060 byte[] bytes = str.getBytes(); 061 byte[] encoded = encode(bytes); 062 try { 063 return new String(encoded, "ASCII"); 064 } catch (UnsupportedEncodingException e) { 065 throw new RuntimeException("ASCII is not supported!", e); 066 } 067 } 068 069 /** 070 * <p> 071 * Encodes a string. 072 * </p> 073 * <p> 074 * Before the string is encoded in Base64, it is converted in a binary 075 * sequence using the supplied charset. 076 * </p> 077 * 078 * @param str 079 * The source string 080 * @param charset 081 * The charset name. 082 * @return The encoded string. 083 * @throws RuntimeException 084 * If an unexpected error occurs. 085 * @since 1.2 086 */ 087 public static String encode(String str, String charset) 088 throws RuntimeException { 089 byte[] bytes; 090 try { 091 bytes = str.getBytes(charset); 092 } catch (UnsupportedEncodingException e) { 093 throw new RuntimeException("Unsupported charset: " + charset, e); 094 } 095 byte[] encoded = encode(bytes); 096 try { 097 return new String(encoded, "ASCII"); 098 } catch (UnsupportedEncodingException e) { 099 throw new RuntimeException("ASCII is not supported!", e); 100 } 101 } 102 103 /** 104 * <p> 105 * Decodes the supplied string. 106 * </p> 107 * <p> 108 * The supplied string is decoded into a binary sequence, and then the 109 * sequence is encoded with the system default charset and returned. 110 * </p> 111 * 112 * @param str 113 * The encoded string. 114 * @return The decoded string. 115 * @throws RuntimeException 116 * If an unexpected error occurs. 117 */ 118 public static String decode(String str) throws RuntimeException { 119 byte[] bytes; 120 try { 121 bytes = str.getBytes("ASCII"); 122 } catch (UnsupportedEncodingException e) { 123 throw new RuntimeException("ASCII is not supported!", e); 124 } 125 byte[] decoded = decode(bytes); 126 return new String(decoded); 127 } 128 129 /** 130 * <p> 131 * Decodes the supplied string. 132 * </p> 133 * <p> 134 * The supplied string is decoded into a binary sequence, and then the 135 * sequence is encoded with the supplied charset and returned. 136 * </p> 137 * 138 * @param str 139 * The encoded string. 140 * @param charset 141 * The charset name. 142 * @return The decoded string. 143 * @throws RuntimeException 144 * If an unexpected error occurs. 145 * @since 1.2 146 */ 147 public static String decode(String str, String charset) 148 throws RuntimeException { 149 byte[] bytes; 150 try { 151 bytes = str.getBytes("ASCII"); 152 } catch (UnsupportedEncodingException e) { 153 throw new RuntimeException("ASCII is not supported!", e); 154 } 155 byte[] decoded = decode(bytes); 156 try { 157 return new String(decoded, charset); 158 } catch (UnsupportedEncodingException e) { 159 throw new RuntimeException("Unsupported charset: " + charset, e); 160 } 161 } 162 163 /** 164 * <p> 165 * Encodes a binary sequence. 166 * </p> 167 * <p> 168 * If data are large, i.e. if you are working with large binary files, 169 * consider to use a {@link Base64OutputStream} instead of loading too much 170 * data in memory. 171 * </p> 172 * 173 * @param bytes 174 * The source sequence. 175 * @return The encoded sequence. 176 * @throws RuntimeException 177 * If an unexpected error occurs. 178 * @since 1.2 179 */ 180 public static byte[] encode(byte[] bytes) throws RuntimeException { 181 return encode(bytes, 0); 182 } 183 184 /** 185 * <p> 186 * Encodes a binary sequence, wrapping every encoded line every 187 * <em>wrapAt</em> characters. A <em>wrapAt</em> value less than 1 disables 188 * wrapping. 189 * </p> 190 * <p> 191 * If data are large, i.e. if you are working with large binary files, 192 * consider to use a {@link Base64OutputStream} instead of loading too much 193 * data in memory. 194 * </p> 195 * 196 * @param bytes 197 * The source sequence. 198 * @param wrapAt 199 * The max line length for encoded data. If less than 1 no wrap 200 * is applied. 201 * @return The encoded sequence. 202 * @throws RuntimeException 203 * If an unexpected error occurs. 204 * @since 1.2 205 */ 206 public static byte[] encode(byte[] bytes, int wrapAt) 207 throws RuntimeException { 208 ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); 209 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 210 try { 211 encode(inputStream, outputStream, wrapAt); 212 } catch (IOException e) { 213 throw new RuntimeException("Unexpected I/O error", e); 214 } finally { 215 try { 216 inputStream.close(); 217 } catch (Throwable t) { 218 ; 219 } 220 try { 221 outputStream.close(); 222 } catch (Throwable t) { 223 ; 224 } 225 } 226 return outputStream.toByteArray(); 227 } 228 229 /** 230 * <p> 231 * Decodes a binary sequence. 232 * </p> 233 * <p> 234 * If data are large, i.e. if you are working with large binary files, 235 * consider to use a {@link Base64InputStream} instead of loading too much 236 * data in memory. 237 * </p> 238 * 239 * @param bytes 240 * The encoded sequence. 241 * @return The decoded sequence. 242 * @throws RuntimeException 243 * If an unexpected error occurs. 244 * @since 1.2 245 */ 246 public static byte[] decode(byte[] bytes) throws RuntimeException { 247 ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); 248 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 249 try { 250 decode(inputStream, outputStream); 251 } catch (IOException e) { 252 throw new RuntimeException("Unexpected I/O error", e); 253 } finally { 254 try { 255 inputStream.close(); 256 } catch (Throwable t) { 257 ; 258 } 259 try { 260 outputStream.close(); 261 } catch (Throwable t) { 262 ; 263 } 264 } 265 return outputStream.toByteArray(); 266 } 267 268 /** 269 * <p> 270 * Encodes data from the given input stream and writes them in the given 271 * output stream. 272 * </p> 273 * <p> 274 * The supplied input stream is read until its end is reached, but it's not 275 * closed by this method. 276 * </p> 277 * <p> 278 * The supplied output stream is nor flushed neither closed by this method. 279 * </p> 280 * 281 * @param inputStream 282 * The input stream. 283 * @param outputStream 284 * The output stream. 285 * @throws IOException 286 * If an I/O error occurs. 287 */ 288 public static void encode(InputStream inputStream, OutputStream outputStream) 289 throws IOException { 290 encode(inputStream, outputStream, 0); 291 } 292 293 /** 294 * <p> 295 * Encodes data from the given input stream and writes them in the given 296 * output stream, wrapping every encoded line every <em>wrapAt</em> 297 * characters. A <em>wrapAt</em> value less than 1 disables wrapping. 298 * </p> 299 * <p> 300 * The supplied input stream is read until its end is reached, but it's not 301 * closed by this method. 302 * </p> 303 * <p> 304 * The supplied output stream is nor flushed neither closed by this method. 305 * </p> 306 * 307 * @param inputStream 308 * The input stream from which clear data are read. 309 * @param outputStream 310 * The output stream in which encoded data are written. 311 * @param wrapAt 312 * The max line length for encoded data. If less than 1 no wrap 313 * is applied. 314 * @throws IOException 315 * If an I/O error occurs. 316 */ 317 public static void encode(InputStream inputStream, 318 OutputStream outputStream, int wrapAt) throws IOException { 319 Base64OutputStream aux = new Base64OutputStream(outputStream, wrapAt); 320 copy(inputStream, aux); 321 aux.commit(); 322 } 323 324 /** 325 * <p> 326 * Decodes data from the given input stream and writes them in the given 327 * output stream. 328 * </p> 329 * <p> 330 * The supplied input stream is read until its end is reached, but it's not 331 * closed by this method. 332 * </p> 333 * <p> 334 * The supplied output stream is nor flushed neither closed by this method. 335 * </p> 336 * 337 * @param inputStream 338 * The input stream from which encoded data are read. 339 * @param outputStream 340 * The output stream in which decoded data are written. 341 * @throws IOException 342 * If an I/O error occurs. 343 */ 344 public static void decode(InputStream inputStream, OutputStream outputStream) 345 throws IOException { 346 copy(new Base64InputStream(inputStream), outputStream); 347 } 348 349 /** 350 * <p> 351 * Encodes data from the given source file contents and writes them in the 352 * given target file, wrapping every encoded line every <em>wrapAt</em> 353 * characters. A <em>wrapAt</em> value less than 1 disables wrapping. 354 * </p> 355 * 356 * @param source 357 * The source file, from which decoded data are read. 358 * @param target 359 * The target file, in which encoded data are written. 360 * @param wrapAt 361 * The max line length for encoded data. If less than 1 no wrap 362 * is applied. 363 * @throws IOException 364 * If an I/O error occurs. 365 * @since 1.3 366 */ 367 public static void encode(File source, File target, int wrapAt) 368 throws IOException { 369 InputStream inputStream = null; 370 OutputStream outputStream = null; 371 try { 372 inputStream = new FileInputStream(source); 373 outputStream = new FileOutputStream(target); 374 Base64.encode(inputStream, outputStream, wrapAt); 375 } finally { 376 if (outputStream != null) { 377 try { 378 outputStream.close(); 379 } catch (Throwable t) { 380 ; 381 } 382 } 383 if (inputStream != null) { 384 try { 385 inputStream.close(); 386 } catch (Throwable t) { 387 ; 388 } 389 } 390 } 391 } 392 393 /** 394 * <p> 395 * Encodes data from the given source file contents and writes them in the 396 * given target file. 397 * </p> 398 * 399 * @param source 400 * The source file, from which decoded data are read. 401 * @param target 402 * The target file, in which encoded data are written. 403 * @throws IOException 404 * If an I/O error occurs. 405 * @since 1.3 406 */ 407 public static void encode(File source, File target) throws IOException { 408 InputStream inputStream = null; 409 OutputStream outputStream = null; 410 try { 411 inputStream = new FileInputStream(source); 412 outputStream = new FileOutputStream(target); 413 Base64.encode(inputStream, outputStream); 414 } finally { 415 if (outputStream != null) { 416 try { 417 outputStream.close(); 418 } catch (Throwable t) { 419 ; 420 } 421 } 422 if (inputStream != null) { 423 try { 424 inputStream.close(); 425 } catch (Throwable t) { 426 ; 427 } 428 } 429 } 430 } 431 432 /** 433 * <p> 434 * Decodes data from the given source file contents and writes them in the 435 * given target file. 436 * </p> 437 * 438 * @param source 439 * The source file, from which encoded data are read. 440 * @param target 441 * The target file, in which decoded data are written. 442 * @throws IOException 443 * If an I/O error occurs. 444 * @since 1.3 445 */ 446 public static void decode(File source, File target) throws IOException { 447 InputStream inputStream = null; 448 OutputStream outputStream = null; 449 try { 450 inputStream = new FileInputStream(source); 451 outputStream = new FileOutputStream(target); 452 decode(inputStream, outputStream); 453 } finally { 454 if (outputStream != null) { 455 try { 456 outputStream.close(); 457 } catch (Throwable t) { 458 ; 459 } 460 } 461 if (inputStream != null) { 462 try { 463 inputStream.close(); 464 } catch (Throwable t) { 465 ; 466 } 467 } 468 } 469 } 470 471 /** 472 * Copies data from a stream to another. 473 * 474 * @param inputStream 475 * The input stream. 476 * @param outputStream 477 * The output stream. 478 * @throws IOException 479 * If a unexpected I/O error occurs. 480 */ 481 private static void copy(InputStream inputStream, OutputStream outputStream) 482 throws IOException { 483 // 1KB buffer 484 byte[] b = new byte[1024]; 485 int len; 486 while ((len = inputStream.read(b)) != -1) { 487 outputStream.write(b, 0, len); 488 } 489 } 490 491 }