001    /*
002     * This file is part of muCommander, http://www.mucommander.com
003     * Copyright (C) 2002-2008 Maxence Bernard
004     *
005     * muCommander is free software; you can redistribute it and/or modify
006     * it under the terms of the GNU General Public License as published by
007     * the Free Software Foundation; either version 3 of the License, or
008     * (at your option) any later version.
009     *
010     * muCommander is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017     */
018    
019    package com.mucommander.io.base64;
020    
021    import java.io.*;
022    
023    /**
024     * <code>Base64Decoder</code> provides methods to ease the decoding of strings and byte arrays in base64.
025     * The {@link Base64InputStream} class is used under the hood to perform the actual base64 decoding.
026     *
027     * @see Base64InputStream
028     * @author Maxence Bernard
029     */
030    public abstract class Base64Decoder {
031    
032        /**
033         * Decodes the given Base64-encoded string and returns the result as a byte array.
034         * Throws an <code>IOException</code> if the String isn't properly Base64-encoded.
035         *
036         * @param s a Base64-encoded String
037         * @return the decoded string as a byte array
038         * @throws java.io.IOException if the given String isn't properly Base64-encoded
039         */
040        public static byte[] decodeAsBytes(String s) throws IOException {
041            byte[] b = s.getBytes();
042    
043            if(b.length%4 != 0) {
044                // Base64 encoded data must come in a multiple of 4 bytes, throw an IOException if it's not the case
045                throw new IOException("Byte array length is not a multiple of 4");
046            }
047    
048            Base64InputStream bin = new Base64InputStream(new ByteArrayInputStream(b));
049            ByteArrayOutputStream bout = new ByteArrayOutputStream();
050            int i;
051    
052            try {
053                while((i=bin.read())!=-1)
054                    bout.write(i);
055    
056                return bout.toByteArray();
057            }
058            finally {
059                bin.close();
060            }
061        }
062    
063        /**
064         * Decodes the given Base64-encoded string and returns the result as a String. The specified encoding is used for
065         * transforming the decoded bytes into a String. Throws an <code>IOException</code> if the String isn't properly
066         * Base64-encoded, or if the encoding is not supported by the Java runtime.
067         *
068         * @param s a Base64-encoded String
069         * @param encoding the character encoding to use for transforming the decoded bytes into a String 
070         * @return the decoded String
071         * @throws UnsupportedEncodingException if the specified encoding is not supported by the Java runtime
072         * @throws java.io.IOException if the given String isn't properly Base64-encoded
073         */
074        public static String decode(String s, String encoding) throws UnsupportedEncodingException, IOException {
075            InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(decodeAsBytes(s)), encoding);
076            StringBuffer sb = new StringBuffer();
077            int i;
078    
079            try {
080                while((i=isr.read())!=-1)
081                    sb.append((char)i);
082    
083                return sb.toString();
084            }
085            finally {
086                isr.close();
087            }
088        }
089    
090        /**
091         * Shorthand for {@link #decode(String, String)} invoked with UTF-8 encoding.
092         *
093         * @param s a Base64-encoded String
094         * @return the decoded String
095         * @throws java.io.IOException if the given String isn't properly Base64-encoded
096         */
097        public static String decode(String s) throws IOException {
098            return decode(s, "UTF-8");
099        }
100    }