001/* Encodes and decodes to and from Base64 notation.
002 * Copyright (C) 2003 "Eric Glass" <jcifs at samba dot org>
003 *
004 * This library is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU Lesser General Public
006 * License as published by the Free Software Foundation; either
007 * version 2.1 of the License, or (at your option) any later version.
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this library; if not, write to the Free Software
016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
017 */
018
019package net.sourceforge.spnego;
020
021public final class Base64 {
022
023    private static final String ALPHABET =
024            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
025
026    private Base64() {
027        // default private
028    }
029    
030    /**
031     * Base-64 encodes the supplied block of data.  Line wrapping is not
032     * applied on output.
033     *
034     * @param bytes The block of data that is to be Base-64 encoded.
035     * @return A <code>String</code> containing the encoded data.
036     */
037    public static String encode(final byte[] bytes) {
038        int length = bytes.length;
039        
040        if (length == 0) {
041            return "";
042        }
043        
044        final StringBuilder buffer =
045                new StringBuilder((int) Math.ceil(length / 3d) * 4);
046        final int remainder = length % 3;
047        length -= remainder;
048        int block;
049        int idx = 0;
050        while (idx < length) {
051            block = ((bytes[idx++] & 0xff) << 16) | ((bytes[idx++] & 0xff) << 8) 
052                | (bytes[idx++] & 0xff);
053            buffer.append(ALPHABET.charAt(block >>> 18));
054            buffer.append(ALPHABET.charAt((block >>> 12) & 0x3f));
055            buffer.append(ALPHABET.charAt((block >>> 6) & 0x3f));
056            buffer.append(ALPHABET.charAt(block & 0x3f));
057        }
058        if (remainder == 0) {
059            return buffer.toString();
060        }
061        if (remainder == 1) {
062            block = (bytes[idx] & 0xff) << 4;
063            buffer.append(ALPHABET.charAt(block >>> 6));
064            buffer.append(ALPHABET.charAt(block & 0x3f));
065            buffer.append("==");
066            return buffer.toString();
067        }
068        block = (((bytes[idx++] & 0xff) << 8) | ((bytes[idx]) & 0xff)) << 2;
069        buffer.append(ALPHABET.charAt(block >>> 12));
070        buffer.append(ALPHABET.charAt((block >>> 6) & 0x3f));
071        buffer.append(ALPHABET.charAt(block & 0x3f));
072        buffer.append("=");
073        return buffer.toString();
074    }
075
076    /**
077     * Decodes the supplied Base-64 encoded string.
078     *
079     * @param string The Base-64 encoded string that is to be decoded.
080     * @return A <code>byte[]</code> containing the decoded data block.
081     */
082    public static byte[] decode(final String string) {
083        final int length = string.length();
084        if (length == 0) {
085            return new byte[0];
086        }
087        
088        final int pad = (string.charAt(length - 2) == '=') ? 2 
089                : (string.charAt(length - 1) == '=') ? 1 : 0;
090        final int size = length * 3 / 4 - pad;
091        final byte[] buffer = new byte[size];
092        int block;
093        int idx = 0;
094        int index = 0;
095        while (idx < length) {
096            block = (ALPHABET.indexOf(string.charAt(idx++)) & 0xff) << 18 
097                | (ALPHABET.indexOf(string.charAt(idx++)) & 0xff) << 12 
098                | (ALPHABET.indexOf(string.charAt(idx++)) & 0xff) << 6 
099                | (ALPHABET.indexOf(string.charAt(idx++)) & 0xff);
100            buffer[index++] = (byte) (block >>> 16);
101            if (index < size) {
102                buffer[index++] = (byte) ((block >>> 8) & 0xff);
103            }
104            if (index < size) {
105                buffer[index++] = (byte) (block & 0xff);
106            }
107        }
108        return buffer;
109    }
110}