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 }