001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *  
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *  
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License. 
018 *  
019 */
020
021package org.apache.directory.shared.util;
022
023
024/**
025 * decoding of base32 characters to raw bytes.
026 * 
027 * TODO: This class isn't used, remove it?
028 * 
029 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
030 */
031public final class Base32
032{
033    /** The available characters */
034    private static final byte[] CHARS = new byte[]{ 
035        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
036        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 
037        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 
038        'Y', 'Z', '2', '3', '4', '5', '6', '7' };
039
040
041    /**
042     * Private constructor.
043     */
044    private Base32()
045    {
046    }
047
048
049    /**
050     * Encodes a string to a Base64 encoded String.
051     *
052     * @param str the string
053     * @return the Base64 encoded string
054     */
055    public static String encode( String str )
056    {
057        if ( Strings.isEmpty(str) )
058        {
059            return "";
060        }
061        
062        byte[] data = Strings.getBytesUtf8(str);
063        int dataLength = data.length;
064        int newLength = ( ( dataLength << 3 ) / 5 ) + ( ( dataLength % 5 ) == 0 ? 0 : 1 );
065        newLength += ( ( newLength % 8 == 0 ) ? 0 : 8 - newLength % 8 );
066        byte[] out = new byte[newLength];
067        
068        int roundLength = (dataLength/5) * 5;
069        int posOut = 0;
070        int posIn = 0;
071        
072        if ( roundLength != 0 )
073        {
074            for ( posIn = 0; posIn < roundLength; posIn += 5 )
075            {
076                byte b0 = data[posIn];
077                byte b1 = data[posIn+1];
078                byte b2 = data[posIn+2];
079                byte b3 = data[posIn+3];
080                byte b4 = data[posIn+4];
081                
082                out[posOut++] = CHARS[( b0 & 0xF8) >> 3];
083                out[posOut++] = CHARS[( ( b0 & 0x07) << 2 ) | ( ( b1 & 0xC0 ) >> 6 ) ];
084                out[posOut++] = CHARS[( b1 & 0x3E) >> 1];
085                out[posOut++] = CHARS[( ( b1 & 0x01) << 4 ) | ( ( b2 & 0xF0 ) >> 4 ) ];
086                out[posOut++] = CHARS[( ( b2 & 0x0F) << 1 ) | ( ( b3 & 0x80 ) >> 7 ) ];
087                out[posOut++] = CHARS[( b3 & 0x7C) >> 2];
088                out[posOut++] = CHARS[( ( b3 & 0x03) << 3 ) | ( ( b4 & 0x70 ) >> 5 )];
089                out[posOut++] = CHARS[b4 & 0x1F];
090            }
091        }
092        
093        int remaining = dataLength - roundLength;
094        
095        switch ( remaining )
096        {
097            case 1 :
098                byte b0 = data[posIn++];
099                
100                out[posOut++] = CHARS[( b0 & 0xF8) >> 3];
101                out[posOut++] = CHARS[( ( b0 & 0x07) << 2 )];
102                out[posOut++] = '=';
103                out[posOut++] = '=';
104                out[posOut++] = '=';
105                out[posOut++] = '=';
106                out[posOut++] = '=';
107                out[posOut++] = '=';
108                break;
109
110            case 2 :
111                b0 = data[posIn++];
112                byte b1 = data[posIn++];
113
114                out[posOut++] = CHARS[( b0 & 0xF8) >> 3];
115                out[posOut++] = CHARS[( ( b0 & 0x07) << 2 ) | ( ( b1 & 0xC0 ) >> 6 ) ];
116                out[posOut++] = CHARS[( b1 & 0x3E) >> 1];
117                out[posOut++] = CHARS[( ( b1 & 0x01) << 4 )];
118                out[posOut++] = '=';
119                out[posOut++] = '=';
120                out[posOut++] = '=';
121                out[posOut++] = '=';
122                break;
123                
124            case 3 :
125                b0 = data[posIn++];
126                b1 = data[posIn++];
127                byte b2 = data[posIn++];
128
129                out[posOut++] = CHARS[( b0 & 0xF8) >> 3];
130                out[posOut++] = CHARS[( ( b0 & 0x07) << 2 ) | ( ( b1 & 0xC0 ) >> 6 ) ];
131                out[posOut++] = CHARS[( b1 & 0x3E) >> 1];
132                out[posOut++] = CHARS[( ( b1 & 0x01) << 4 ) | ( ( b2 & 0xF0 ) >> 4 ) ];
133                out[posOut++] = CHARS[( ( b2 & 0x0F) << 1 ) ];
134                out[posOut++] = '=';
135                out[posOut++] = '=';
136                out[posOut++] = '=';
137                break;
138                
139            case 4 :
140                b0 = data[posIn++];
141                b1 = data[posIn++];
142                b2 = data[posIn++];
143                byte b3 = data[posIn++];
144
145                out[posOut++] = CHARS[( b0 & 0xF8) >> 3];
146                out[posOut++] = CHARS[( ( b0 & 0x07) << 2 ) | ( ( b1 & 0xC0 ) >> 6 ) ];
147                out[posOut++] = CHARS[( b1 & 0x3E) >> 1];
148                out[posOut++] = CHARS[( ( b1 & 0x01) << 4 ) | ( ( b2 & 0xF0 ) >> 4 ) ];
149                out[posOut++] = CHARS[( ( b2 & 0x0F) << 1 ) | ( ( b3 & 0x80 ) >> 7 ) ];
150                out[posOut++] = CHARS[( b3 & 0x7C) >> 2];
151                out[posOut++] = CHARS[( ( b3 & 0x03) << 3 ) ];
152                out[posOut++] = '=';
153                break;
154        }
155        
156        return Strings.utf8ToString(out);
157    }
158}