/******************************************************************************* * $Id$ * $Author$ * $Date$ * * Copyright 2002 - YAJUL Developers, Joshua Davis, Kent Vogel. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * ******************************************************************************/ // --- The orgiginal code is from: --- // Base64Decoder.java // $Id$ // (c) COPYRIGHT MIT and INRIA, 1996. // Please first read the full copyright statement in file COPYRIGHT.html package org.yajul.io; import java.io.*; /** * Decode a BASE64 encoded input stream to some output stream. * This class implements BASE64 decoding, as specified in the * <a href="http://ds.internic.net/rfc/rfc1521.txt">MIME specification</a>. * * @author josh (Refactored to use stream filter) * @see org.yajul.io.Base64Encoder */ public class Base64Decoder { /** * Convenience method that will decode the given string. * * @param input The input string * @return String - the decoded string. * @throws org.yajul.io.Base64FormatException * if the input is not valid. */ public static String decode(String input) throws Base64FormatException { Base64Decoder dec = new Base64Decoder(input); return dec.processString(); } /** * Convenience method that will decode the given byte array. * * @param input The input byte array * @return String - the decoded byte array. * @throws org.yajul.io.Base64FormatException * if the input is not valid. */ public static byte[] decode(byte[] input) throws Base64FormatException { return decode(input, 0, input.length); } /** * Convenience method that will decode the given byte array. * * @param input The input byte array * @param offset The offset in the buffer of the first byte to read. * @param length The maximum number of bytes to read from the buffer. * @return String - the decoded byte array. * @throws org.yajul.io.Base64FormatException * if the input is not valid. */ public static byte[] decode(byte[] input, int offset, int length) throws Base64FormatException { Base64Decoder dec = new Base64Decoder(input, offset, length); try { dec.process(); } catch (IOException e) { throw new Base64FormatException("Unable to decode input due to: " + e.getMessage()); } return dec.toByteArray(); } private InputStream in = null; private OutputStream out = null; private boolean byteArrayOutputStream = false; /** * Default constructor. */ public Base64Decoder() { } /** * Create a decoder to decode a stream. * * @param in The input stream (to be decoded). * @param out The output stream, to write decoded data to. */ public Base64Decoder(InputStream in, OutputStream out) { this.in = in; this.out = out; this.byteArrayOutputStream = false; } /** * Create a decoder to decode a String. * * @param input The string to be decoded. */ public Base64Decoder(String input) { try { byte[] bytes = input.getBytes("ISO8859_1"); initialize(bytes, 0, bytes.length); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(this.getClass().getName() + "[Constructor] Unable to convert" + "properly char to bytes"); } } /** * Creates a decoder that will decode the specified array of bytes. * * @param bytes The array of bytes to be decoded. * @param offset The offset in the buffer of the first byte to read. * @param length The maximum number of bytes to read from the buffer. */ public Base64Decoder(byte[] bytes, int offset, int length) { initialize(bytes, offset, length); } /** * Initializes the decoder with an array of base 64 encoded bytes. * * @param bytes The array of bytes to be decoded. * @param offset The offset in the buffer of the first byte to read. * @param length The maximum number of bytes to read from the buffer. */ public void initialize(byte[] bytes, int offset, int length) { this.byteArrayOutputStream = true; this.in = new ByteArrayInputStream(bytes, offset, length); this.out = new ByteArrayOutputStream(); } /** * Do the actual decoding. * Process the input stream by decoding it and emiting the resulting bytes * into the output stream. * * @throws java.io.IOException If the input or output stream accesses failed. * @throws org.yajul.io.Base64FormatException * If the input stream is not compliant * with the BASE64 specification. */ public void process() throws IOException { Base64InputStream decodedInput = new Base64InputStream(in); StreamCopier.unsyncCopy(decodedInput, out, 16); out.flush(); } /** * Do the decoding, and return a String. * This methods should be called when the decoder is used in * <em>String</em> mode. It decodes the input string to an output string * that is returned. * <br> * Throws: RuntimeException If the object wasn't constructed to * decode a String. * * @return String - The decoded string. * @throws org.yajul.io.Base64FormatException * If the input string is not compliant * with the BASE64 specification. */ public String processString() throws Base64FormatException { if (!byteArrayOutputStream) throw new IllegalStateException(this.getClass().getName() + ".processString() : " + "Not initialized properly for this operation."); try { process(); } catch (IOException e) { throw new Base64FormatException("Unexpected IOException: " + e.getMessage()); } String s; try { s = ((ByteArrayOutputStream) out).toString("ISO8859_1"); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(this.getClass().getName() + "[processString] Unable to convert" + "properly char to bytes"); } return s; } /** * Returns the byte array that is the result of the decoding the input * array of bytes. The instance must have been initialized using * the initialize(byte[]) method. * * @return byte[] An array of decoded bytes. */ public byte[] toByteArray() { if (!byteArrayOutputStream) throw new IllegalStateException(this.getClass().getName() + ".toByteArray() : " + "Not initialized properly for this operation."); return ((ByteArrayOutputStream) out).toByteArray(); } }