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    
021    package org.apache.directory.shared.ldap.util;
022    
023    
024    /**
025     * decoding of base32 characters to raw bytes.
026     * 
027     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
028     * @version $Revision: 664290 $
029     */
030    public class Base32
031    {
032        private static byte[] CHARS = new byte[]{ 
033            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
034            'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 
035            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 
036            'Y', 'Z', '2', '3', '4', '5', '6', '7' };
037        
038    
039        public static String encode( String str )
040        {
041            if ( StringTools.isEmpty( str ) )
042            {
043                return "";
044            }
045            
046            byte[] data = StringTools.getBytesUtf8( str );
047            int dataLength = data.length;
048            int newLength = ( ( dataLength << 3 ) / 5 ) + ( ( dataLength % 5 ) == 0 ? 0 : 1 );
049            newLength += ( ( newLength % 8 == 0 ) ? 0 : 8 - newLength % 8 );
050            byte[] out = new byte[newLength];
051            
052            int roundLength = (dataLength/5) * 5;
053            int posOut = 0;
054            int posIn = 0;
055            
056            if ( roundLength != 0 )
057            {
058                for ( posIn = 0; posIn < roundLength; posIn += 5 )
059                {
060                    byte b0 = data[posIn];
061                    byte b1 = data[posIn+1];
062                    byte b2 = data[posIn+2];
063                    byte b3 = data[posIn+3];
064                    byte b4 = data[posIn+4];
065                    
066                    out[posOut++] = CHARS[( b0 & 0xF8) >> 3];
067                    out[posOut++] = CHARS[( ( b0 & 0x07) << 2 ) | ( ( b1 & 0xC0 ) >> 6 ) ];
068                    out[posOut++] = CHARS[( b1 & 0x3E) >> 1];
069                    out[posOut++] = CHARS[( ( b1 & 0x01) << 4 ) | ( ( b2 & 0xF0 ) >> 4 ) ];
070                    out[posOut++] = CHARS[( ( b2 & 0x0F) << 1 ) | ( ( b3 & 0x80 ) >> 7 ) ];
071                    out[posOut++] = CHARS[( b3 & 0x7C) >> 2];
072                    out[posOut++] = CHARS[( ( b3 & 0x03) << 3 ) | ( ( b4 & 0x70 ) >> 5 )];
073                    out[posOut++] = CHARS[b4 & 0x1F];
074                }
075            }
076            
077            int remaining = dataLength - roundLength;
078            
079            switch ( remaining )
080            {
081                case 1 :
082                    byte b0 = data[posIn++];
083                    
084                    out[posOut++] = CHARS[( b0 & 0xF8) >> 3];
085                    out[posOut++] = CHARS[( ( b0 & 0x07) << 2 )];
086                    out[posOut++] = '=';
087                    out[posOut++] = '=';
088                    out[posOut++] = '=';
089                    out[posOut++] = '=';
090                    out[posOut++] = '=';
091                    out[posOut++] = '=';
092                    break;
093    
094                case 2 :
095                    b0 = data[posIn++];
096                    byte b1 = data[posIn++];
097    
098                    out[posOut++] = CHARS[( b0 & 0xF8) >> 3];
099                    out[posOut++] = CHARS[( ( b0 & 0x07) << 2 ) | ( ( b1 & 0xC0 ) >> 6 ) ];
100                    out[posOut++] = CHARS[( b1 & 0x3E) >> 1];
101                    out[posOut++] = CHARS[( ( b1 & 0x01) << 4 )];
102                    out[posOut++] = '=';
103                    out[posOut++] = '=';
104                    out[posOut++] = '=';
105                    out[posOut++] = '=';
106                    break;
107                    
108                case 3 :
109                    b0 = data[posIn++];
110                    b1 = data[posIn++];
111                    byte b2 = data[posIn++];
112    
113                    out[posOut++] = CHARS[( b0 & 0xF8) >> 3];
114                    out[posOut++] = CHARS[( ( b0 & 0x07) << 2 ) | ( ( b1 & 0xC0 ) >> 6 ) ];
115                    out[posOut++] = CHARS[( b1 & 0x3E) >> 1];
116                    out[posOut++] = CHARS[( ( b1 & 0x01) << 4 ) | ( ( b2 & 0xF0 ) >> 4 ) ];
117                    out[posOut++] = CHARS[( ( b2 & 0x0F) << 1 ) ];
118                    out[posOut++] = '=';
119                    out[posOut++] = '=';
120                    out[posOut++] = '=';
121                    break;
122                    
123                case 4 :
124                    b0 = data[posIn++];
125                    b1 = data[posIn++];
126                    b2 = data[posIn++];
127                    byte b3 = 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 ) | ( ( b3 & 0x80 ) >> 7 ) ];
134                    out[posOut++] = CHARS[( b3 & 0x7C) >> 2];
135                    out[posOut++] = CHARS[( ( b3 & 0x03) << 3 ) ];
136                    out[posOut++] = '=';
137                    break;
138            }
139            
140            return StringTools.utf8ToString( out );
141        }
142    }