001 /* 002 * Java Base64 - A pure Java library for reading and writing Base64 003 * encoded streams. 004 * 005 * Copyright (C) 2008 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 General Public License as published by 009 * the Free Software Foundation, either version 3 of the License, or 010 * (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with this program. 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.IOException; 025 import java.io.InputStream; 026 import java.io.OutputStream; 027 import java.io.UnsupportedEncodingException; 028 029 /** 030 * <p> 031 * Base64 encoding and decoding utility methods, both for binary and textual 032 * informations. 033 * </p> 034 * 035 * @author Carlo Pelliccia 036 * @since 1.1 037 * @version 1.2 038 */ 039 public class Base64 { 040 041 /** 042 * <p> 043 * Encodes a string. 044 * </p> 045 * <p> 046 * Before the string is encoded in Base64, it is converted in a binary 047 * sequence using the system default charset. 048 * </p> 049 * 050 * @param str 051 * The source string. 052 * @return The encoded string. 053 * @throws RuntimeException 054 * If an unexpected error occurs. 055 */ 056 public static String encode(String str) throws RuntimeException { 057 byte[] bytes = str.getBytes(); 058 byte[] encoded = encode(bytes); 059 try { 060 return new String(encoded, "ASCII"); 061 } catch (UnsupportedEncodingException e) { 062 throw new RuntimeException("ASCII is not supported!", e); 063 } 064 } 065 066 /** 067 * <p> 068 * Encodes a string. 069 * </p> 070 * <p> 071 * Before the string is encoded in Base64, it is converted in a binary 072 * sequence using the supplied charset. 073 * </p> 074 * 075 * @param str 076 * The source string 077 * @param charset 078 * The charset name. 079 * @return The encoded string. 080 * @throws RuntimeException 081 * If an unexpected error occurs. 082 * @since 1.2 083 */ 084 public static String encode(String str, String charset) 085 throws RuntimeException { 086 byte[] bytes; 087 try { 088 bytes = str.getBytes(charset); 089 } catch (UnsupportedEncodingException e) { 090 throw new RuntimeException("Unsupported charset: " + charset, e); 091 } 092 byte[] encoded = encode(bytes); 093 try { 094 return new String(encoded, "ASCII"); 095 } catch (UnsupportedEncodingException e) { 096 throw new RuntimeException("ASCII is not supported!", e); 097 } 098 } 099 100 /** 101 * <p> 102 * Decodes the supplied string. 103 * </p> 104 * <p> 105 * The supplied string is decoded into a binary sequence, and then the 106 * sequence is encoded with the system default charset and returned. 107 * </p> 108 * 109 * @param str 110 * The encoded string. 111 * @return The decoded string. 112 * @throws RuntimeException 113 * If an unexpected error occurs. 114 */ 115 public static String decode(String str) throws RuntimeException { 116 byte[] bytes; 117 try { 118 bytes = str.getBytes("ASCII"); 119 } catch (UnsupportedEncodingException e) { 120 throw new RuntimeException("ASCII is not supported!", e); 121 } 122 byte[] decoded = decode(bytes); 123 return new String(decoded); 124 } 125 126 /** 127 * <p> 128 * Decodes the supplied string. 129 * </p> 130 * <p> 131 * The supplied string is decoded into a binary sequence, and then the 132 * sequence is encoded with the supplied charset and returned. 133 * </p> 134 * 135 * @param str 136 * The encoded string. 137 * @param charset 138 * The charset name. 139 * @return The decoded string. 140 * @throws RuntimeException 141 * If an unexpected error occurs. 142 * @since 1.2 143 */ 144 public static String decode(String str, String charset) 145 throws RuntimeException { 146 byte[] bytes; 147 try { 148 bytes = str.getBytes("ASCII"); 149 } catch (UnsupportedEncodingException e) { 150 throw new RuntimeException("ASCII is not supported!", e); 151 } 152 byte[] decoded = decode(bytes); 153 try { 154 return new String(decoded, charset); 155 } catch (UnsupportedEncodingException e) { 156 throw new RuntimeException("Unsupported charset: " + charset, e); 157 } 158 } 159 160 /** 161 * <p> 162 * Encodes a binary sequence. 163 * </p> 164 * <p> 165 * If data are large, i.e. if you are working with large binary files, 166 * consider to use a {@link Base64OutputStream} instead of loading too much 167 * data in memory. 168 * </p> 169 * 170 * @param bytes 171 * The source sequence. 172 * @return The encoded sequence. 173 * @throws RuntimeException 174 * If an unexpected error occurs. 175 * @since 1.2 176 */ 177 public static byte[] encode(byte[] bytes) throws RuntimeException { 178 return encode(bytes, 0); 179 } 180 181 /** 182 * <p> 183 * Encodes a binary sequence, wrapping every encoded line every 184 * <em>wrapAt</em> characters. A <em>wrapAt</em> value less than 1 disables 185 * wrapping. 186 * </p> 187 * <p> 188 * If data are large, i.e. if you are working with large binary files, 189 * consider to use a {@link Base64OutputStream} instead of loading too much 190 * data in memory. 191 * </p> 192 * 193 * @param bytes 194 * The source sequence. 195 * @param wrapAt 196 * The max line length for encoded data. If less than 1 no wrap 197 * is applied. 198 * @return The encoded sequence. 199 * @throws RuntimeException 200 * If an unexpected error occurs. 201 * @since 1.2 202 */ 203 public static byte[] encode(byte[] bytes, int wrapAt) 204 throws RuntimeException { 205 ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); 206 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 207 try { 208 encode(inputStream, outputStream, wrapAt); 209 } catch (IOException e) { 210 throw new RuntimeException("Unexpected I/O error", e); 211 } finally { 212 try { 213 inputStream.close(); 214 } catch (Throwable t) { 215 ; 216 } 217 try { 218 outputStream.close(); 219 } catch (Throwable t) { 220 ; 221 } 222 } 223 return outputStream.toByteArray(); 224 } 225 226 /** 227 * <p> 228 * Decodes a binary sequence. 229 * </p> 230 * <p> 231 * If data are large, i.e. if you are working with large binary files, 232 * consider to use a {@link Base64InputStream} instead of loading too much 233 * data in memory. 234 * </p> 235 * 236 * @param bytes 237 * The encoded sequence. 238 * @return The decoded sequence. 239 * @throws RuntimeException 240 * If an unexpected error occurs. 241 * @since 1.2 242 */ 243 public static byte[] decode(byte[] bytes) throws RuntimeException { 244 ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); 245 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 246 try { 247 decode(inputStream, outputStream); 248 } catch (IOException e) { 249 throw new RuntimeException("Unexpected I/O error", e); 250 } finally { 251 try { 252 inputStream.close(); 253 } catch (Throwable t) { 254 ; 255 } 256 try { 257 outputStream.close(); 258 } catch (Throwable t) { 259 ; 260 } 261 } 262 return outputStream.toByteArray(); 263 } 264 265 /** 266 * <p> 267 * Encodes data from the given input stream and write them in the given 268 * output stream. 269 * </p> 270 * <p> 271 * The supplied input stream is read until its end is reached, but it's not 272 * closed by this method. 273 * </p> 274 * <p> 275 * The supplied output stream is nor flushed neither closed by this method. 276 * </p> 277 * 278 * @param inputStream 279 * The input stream. 280 * @param outputStream 281 * The output stream. 282 * @throws IOException 283 * If an I/O error occurs. 284 */ 285 public static void encode(InputStream inputStream, OutputStream outputStream) 286 throws IOException { 287 encode(inputStream, outputStream, 0); 288 } 289 290 /** 291 * <p> 292 * Encodes data from the given input stream and write them in the given 293 * output stream, wrapping every encoded line every <em>wrapAt</em> 294 * characters. A <em>wrapAt</em> value less than 1 disables wrapping. 295 * </p> 296 * <p> 297 * The supplied input stream is read until its end is reached, but it's not 298 * closed by this method. 299 * </p> 300 * <p> 301 * The supplied output stream is nor flushed neither closed by this method. 302 * </p> 303 * 304 * @param inputStream 305 * The input stream from which clear data are read. 306 * @param outputStream 307 * The output stream in which encoded data are written. 308 * @param wrapAt 309 * The max line length for encoded data. If less than 1 no wrap 310 * is applied. 311 * @throws IOException 312 * If an I/O error occurs. 313 */ 314 public static void encode(InputStream inputStream, 315 OutputStream outputStream, int wrapAt) throws IOException { 316 Base64OutputStream aux = new Base64OutputStream(outputStream); 317 copy(inputStream, aux); 318 aux.commit(); 319 } 320 321 /** 322 * <p> 323 * Decodes data from the given input stream and write them in the given 324 * output stream. 325 * </p> 326 * <p> 327 * The supplied input stream is read until its end is reached, but it's not 328 * closed by this method. 329 * </p> 330 * <p> 331 * The supplied output stream is nor flushed neither closed by this method. 332 * </p> 333 * 334 * @param inputStream 335 * The input stream from which encoded data are read. 336 * @param outputStream 337 * The output stream in which decoded data are written. 338 * @throws IOException 339 * If an I/O error occurs. 340 */ 341 public static void decode(InputStream inputStream, OutputStream outputStream) 342 throws IOException { 343 copy(new Base64InputStream(inputStream), outputStream); 344 } 345 346 /** 347 * Copies data from a stream to another. 348 * 349 * @param inputStream 350 * The input stream. 351 * @param outputStream 352 * The output stream. 353 * @throws IOException 354 * If a unexpected I/O error occurs. 355 */ 356 private static void copy(InputStream inputStream, OutputStream outputStream) 357 throws IOException { 358 // 1KB buffer 359 byte[] b = new byte[1024]; 360 int len; 361 while ((len = inputStream.read(b)) != -1) { 362 outputStream.write(b, 0, len); 363 } 364 } 365 366 }