001    package net.sourceforge.spnego;
002    
003    /* Encodes and decodes to and from Base64 notation.
004     * Copyright (C) 2003 "Eric Glass" <jcifs at samba dot org>
005     *
006     * This library is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 2.1 of the License, or (at your option) any later version.
010     *
011     * This library 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 GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with this library; if not, write to the Free Software
018     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
019     */
020    
021    public 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            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    }