/* * Java Base64 - A pure Java library for reading and writing Base64 * encoded streams. * * Copyright (C) 2007-2009 Carlo Pelliccia (www.sauronsoftware.it) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version * 2.1, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License version 2.1 along with this program. * If not, see <http://www.gnu.org/licenses/>. */ package com.mjitech.qa.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; /** * <p> * Base64 encoding and decoding utility methods, both for binary and textual * informations. * </p> * * @author Carlo Pelliccia * @since 1.1 * @version 1.3 */ public class Base64 { private static byte[] base64DecodeChars = new byte[]{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1}; /** * <p> * Encodes a string. * </p> * <p> * Before the string is encoded in Base64, it is converted in a binary * sequence using the system default charset. * </p> * * @param str * The source string. * @return The encoded string. * @throws RuntimeException * If an unexpected error occurs. */ public static String encode(String str) throws RuntimeException { byte[] bytes = str.getBytes(); byte[] encoded = encode(bytes); try { return new String(encoded, "ASCII"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("ASCII is not supported!", e); } } /** * <p> * Encodes a string. * </p> * <p> * Before the string is encoded in Base64, it is converted in a binary * sequence using the supplied charset. * </p> * * @param str * The source string * @param charset * The charset name. * @return The encoded string. * @throws RuntimeException * If an unexpected error occurs. * @since 1.2 */ public static String encode(String str, String charset) throws RuntimeException { byte[] bytes; try { bytes = str.getBytes(charset); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Unsupported charset: " + charset, e); } byte[] encoded = encode(bytes); try { return new String(encoded, "ASCII"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("ASCII is not supported!", e); } } /** * <p> * Decodes the supplied string. * </p> * <p> * The supplied string is decoded into a binary sequence, and then the * sequence is encoded with the system default charset and returned. * </p> * * @param str * The encoded string. * @return The decoded string. * @throws RuntimeException * If an unexpected error occurs. */ public static byte[] decode(String str) throws UnsupportedEncodingException { StringBuffer sb = new StringBuffer(); byte[] data = str.getBytes("US-ASCII"); int len = data.length; int i = 0; int b1, b2, b3, b4; while (i < len) { do { b1 = base64DecodeChars[data[i++]]; } while (i < len && b1 == -1); if (b1 == -1) break; do { b2 = base64DecodeChars [data[i++]]; } while (i < len && b2 == -1); if (b2 == -1) break; sb.append((char) ((b1 << 2) | ((b2 & 0x30) >>> 4))); do { b3 = data[i++]; if (b3 == 61) return sb.toString().getBytes("iso8859-1"); b3 = base64DecodeChars[b3]; } while (i < len && b3 == -1); if (b3 == -1) break; sb.append((char) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2))); do { b4 = data[i++]; if (b4 == 61) return sb.toString().getBytes("iso8859-1"); b4 = base64DecodeChars[b4]; } while (i < len && b4 == -1); if (b4 == -1) break; sb.append((char) (((b3 & 0x03) << 6) | b4)); } return sb.toString().getBytes("iso8859-1"); } /** * <p> * Decodes the supplied string. * </p> * <p> * The supplied string is decoded into a binary sequence, and then the * sequence is encoded with the supplied charset and returned. * </p> * * @param str * The encoded string. * @param charset * The charset name. * @return The decoded string. * @throws RuntimeException * If an unexpected error occurs. * @since 1.2 */ public static String decode(String str, String charset) throws RuntimeException { byte[] bytes; try { bytes = str.getBytes("ASCII"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("ASCII is not supported!", e); } byte[] decoded = decode(bytes); try { return new String(decoded, charset); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Unsupported charset: " + charset, e); } } /** * <p> * Encodes a binary sequence. * </p> * <p> * If data are large, i.e. if you are working with large binary files, * consider to use a {@link Base64OutputStream} instead of loading too much * data in memory. * </p> * * @param bytes * The source sequence. * @return The encoded sequence. * @throws RuntimeException * If an unexpected error occurs. * @since 1.2 */ public static byte[] encode(byte[] bytes) throws RuntimeException { return encode(bytes, 0); } /** * <p> * Encodes a binary sequence, wrapping every encoded line every * <em>wrapAt</em> characters. A <em>wrapAt</em> value less than 1 disables * wrapping. * </p> * <p> * If data are large, i.e. if you are working with large binary files, * consider to use a {@link Base64OutputStream} instead of loading too much * data in memory. * </p> * * @param bytes * The source sequence. * @param wrapAt * The max line length for encoded data. If less than 1 no wrap * is applied. * @return The encoded sequence. * @throws RuntimeException * If an unexpected error occurs. * @since 1.2 */ public static byte[] encode(byte[] bytes, int wrapAt) throws RuntimeException { ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { encode(inputStream, outputStream, wrapAt); } catch (IOException e) { throw new RuntimeException("Unexpected I/O error", e); } finally { try { inputStream.close(); } catch (Throwable t) { ; } try { outputStream.close(); } catch (Throwable t) { ; } } return outputStream.toByteArray(); } /** * <p> * Decodes a binary sequence. * </p> * <p> * If data are large, i.e. if you are working with large binary files, * consider to use a {@link Base64InputStream} instead of loading too much * data in memory. * </p> * * @param bytes * The encoded sequence. * @return The decoded sequence. * @throws RuntimeException * If an unexpected error occurs. * @since 1.2 */ public static byte[] decode(byte[] bytes) throws RuntimeException { ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { decode(inputStream, outputStream); } catch (IOException e) { throw new RuntimeException("Unexpected I/O error", e); } finally { try { inputStream.close(); } catch (Throwable t) { ; } try { outputStream.close(); } catch (Throwable t) { ; } } return outputStream.toByteArray(); } /** * <p> * Encodes data from the given input stream and writes them in the given * output stream. * </p> * <p> * The supplied input stream is read until its end is reached, but it's not * closed by this method. * </p> * <p> * The supplied output stream is nor flushed neither closed by this method. * </p> * * @param inputStream * The input stream. * @param outputStream * The output stream. * @throws IOException * If an I/O error occurs. */ public static void encode(InputStream inputStream, OutputStream outputStream) throws IOException { encode(inputStream, outputStream, 0); } /** * <p> * Encodes data from the given input stream and writes them in the given * output stream, wrapping every encoded line every <em>wrapAt</em> * characters. A <em>wrapAt</em> value less than 1 disables wrapping. * </p> * <p> * The supplied input stream is read until its end is reached, but it's not * closed by this method. * </p> * <p> * The supplied output stream is nor flushed neither closed by this method. * </p> * * @param inputStream * The input stream from which clear data are read. * @param outputStream * The output stream in which encoded data are written. * @param wrapAt * The max line length for encoded data. If less than 1 no wrap * is applied. * @throws IOException * If an I/O error occurs. */ public static void encode(InputStream inputStream, OutputStream outputStream, int wrapAt) throws IOException { Base64OutputStream aux = new Base64OutputStream(outputStream, wrapAt); copy(inputStream, aux); aux.commit(); } /** * <p> * Decodes data from the given input stream and writes them in the given * output stream. * </p> * <p> * The supplied input stream is read until its end is reached, but it's not * closed by this method. * </p> * <p> * The supplied output stream is nor flushed neither closed by this method. * </p> * * @param inputStream * The input stream from which encoded data are read. * @param outputStream * The output stream in which decoded data are written. * @throws IOException * If an I/O error occurs. */ public static void decode(InputStream inputStream, OutputStream outputStream) throws IOException { copy(new Base64InputStream(inputStream), outputStream); } /** * <p> * Encodes data from the given source file contents and writes them in the * given target file, wrapping every encoded line every <em>wrapAt</em> * characters. A <em>wrapAt</em> value less than 1 disables wrapping. * </p> * * @param source * The source file, from which decoded data are read. * @param target * The target file, in which encoded data are written. * @param wrapAt * The max line length for encoded data. If less than 1 no wrap * is applied. * @throws IOException * If an I/O error occurs. * @since 1.3 */ public static void encode(File source, File target, int wrapAt) throws IOException { InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = new FileInputStream(source); outputStream = new FileOutputStream(target); Base64.encode(inputStream, outputStream, wrapAt); } finally { if (outputStream != null) { try { outputStream.close(); } catch (Throwable t) { ; } } if (inputStream != null) { try { inputStream.close(); } catch (Throwable t) { ; } } } } /** * <p> * Encodes data from the given source file contents and writes them in the * given target file. * </p> * * @param source * The source file, from which decoded data are read. * @param target * The target file, in which encoded data are written. * @throws IOException * If an I/O error occurs. * @since 1.3 */ public static void encode(File source, File target) throws IOException { InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = new FileInputStream(source); outputStream = new FileOutputStream(target); Base64.encode(inputStream, outputStream); } finally { if (outputStream != null) { try { outputStream.close(); } catch (Throwable t) { ; } } if (inputStream != null) { try { inputStream.close(); } catch (Throwable t) { ; } } } } /** * <p> * Decodes data from the given source file contents and writes them in the * given target file. * </p> * * @param source * The source file, from which encoded data are read. * @param target * The target file, in which decoded data are written. * @throws IOException * If an I/O error occurs. * @since 1.3 */ public static void decode(File source, File target) throws IOException { InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = new FileInputStream(source); outputStream = new FileOutputStream(target); decode(inputStream, outputStream); } finally { if (outputStream != null) { try { outputStream.close(); } catch (Throwable t) { ; } } if (inputStream != null) { try { inputStream.close(); } catch (Throwable t) { ; } } } } /** * Copies data from a stream to another. * * @param inputStream * The input stream. * @param outputStream * The output stream. * @throws IOException * If a unexpected I/O error occurs. */ private static void copy(InputStream inputStream, OutputStream outputStream) throws IOException { // 1KB buffer byte[] b = new byte[1024]; int len; while ((len = inputStream.read(b)) != -1) { outputStream.write(b, 0, len); } } }