001/**
002 * Java Web Archive Toolkit - Software to read and validate ARC, WARC
003 * and GZip files. (http://jwat.org/)
004 * Copyright 2011-2012 Netarkivet.dk (http://netarkivet.dk/)
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * 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, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.jwat.common;
019
020import java.io.ByteArrayOutputStream;
021import java.util.Arrays;
022
023/**
024 * Base32 encoder/decoder implementation based on the specifications in
025 * rfc3548.
026 *
027 * @author nicl
028 */
029public class Base32 {
030
031    /** Ascii table used to encode. */
032    public static String encodeTab = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
033
034    /** Table used to decode. */
035    public static byte[] decodeTab = new byte[ 256 ];
036
037    /** Populate decode table. */
038    static {
039        Arrays.fill( decodeTab, (byte)0xff );
040        for ( int i=0; i<encodeTab.length(); ++i ) {
041            decodeTab[ Character.toUpperCase( encodeTab.charAt( i ) ) ] = (byte)i;
042            decodeTab[ Character.toLowerCase( encodeTab.charAt( i ) ) ] = (byte)i;
043        }
044    }
045
046    /**
047     * Static class.
048     */
049    protected Base32() {
050    }
051
052    /**
053     * Decodes an encoded string.
054     * @param in encoded string.
055     * @param bStrict if true checks for the correct number of trailing "="
056     * @return decoded string or null
057     */
058    public static String decodeToString(String in, boolean bStrict) {
059        if (in == null) {
060            return null;
061        }
062        if (in.length() == 0) {
063            return "";
064        }
065
066        StringBuffer out = new StringBuffer( 256 );
067
068        boolean b = true;
069        int idx = 0;
070        char cin;
071        int mod = 0;
072        int cIdx;
073        int cout = 0;
074
075        /*
076         * Loop.
077         */
078
079        while ( b ) {
080            if ( idx < in.length() ) {
081                cin = in.charAt( idx );
082                if ( cin == '=' ) {
083                    b = false;
084                }
085                else {
086                    ++idx;
087                    cIdx = decodeTab[ cin ];
088                    if ( cIdx != -1 ) {
089                        switch ( mod ) {
090                            case 0:
091                                cout = cIdx << 3;
092                                break;
093                            case 1:
094                                cout |= (cIdx >> 2);
095                                out.append( (char)cout );
096                                cout = (cIdx << 6) & 255;
097                                break;
098                            case 2:
099                                cout |= (cIdx << 1);
100                                break;
101                            case 3:
102                                cout |= (cIdx >> 4);
103                                out.append( (char)cout );
104                                cout = (cIdx << 4) & 255;
105                                break;
106                            case 4:
107                                cout |= (cIdx >> 1);
108                                out.append( (char)cout );
109                                cout = (cIdx << 7) & 255;
110                                break;
111                            case 5:
112                                cout |= cIdx << 2;
113                                break;
114                            case 6:
115                                cout |= (cIdx >> 3);
116                                out.append( (char)cout );
117                                cout = (cIdx << 5) & 255;
118                                break;
119                            case 7:
120                                cout |= cIdx;
121                                out.append( (char)cout );
122                                break;
123                        }
124                        mod = ( mod + 1 ) % 8;
125                    }
126                    else {
127                        return null;
128                    }
129                }
130            }
131            else {
132                b = false;
133            }
134        }
135
136        /*
137         * Padding.
138         */
139
140        switch ( mod ) {
141        case 1:
142               // In state 1 only 5 bits of the next 40 bit has been decoded.
143        case 3:
144            // In state 3 1 bit must have also been written in the next byte.
145        case 6:
146            // In state 6 2 bits must have also been written in the next byte.
147            return null;
148        default:
149            if ( bStrict ) {
150                while ( mod != 0 && idx < in.length() && in.charAt( idx ) == '=' ) {
151                    ++idx;
152                    mod = ( mod + 1 ) % 8;
153                }
154                if (mod != 0 || idx < in.length() ) {
155                    return null;
156                }
157            }
158            break;
159        }
160        return out.toString();
161    }
162
163    /**
164     * Decodes an encoded string.
165     * @param in encoded string.
166     * @param bStrict if true checks for the correct number of trailing "="
167     * @return decoded byte array or null
168     */
169    public static byte[] decodeToArray(String in, boolean bStrict) {
170        if (in == null) {
171            return null;
172        }
173        if (in.length() == 0) {
174            return new byte[0];
175        }
176
177        ByteArrayOutputStream out = new ByteArrayOutputStream();
178
179        boolean b = true;
180        int idx = 0;
181        char cin;
182        int mod = 0;
183        int cIdx;
184        int cout = 0;
185
186        /*
187         * Loop.
188         */
189
190        while ( b ) {
191            if ( idx < in.length() ) {
192                cin = in.charAt( idx );
193                if ( cin == '=' ) {
194                    b = false;
195                }
196                else {
197                    ++idx;
198                    cIdx = decodeTab[ cin ];
199                    if ( cIdx != -1 ) {
200                        switch ( mod ) {
201                            case 0:
202                                cout = cIdx << 3;
203                                break;
204                            case 1:
205                                cout |= (cIdx >> 2);
206                                out.write( cout );
207                                cout = (cIdx << 6) & 255;
208                                break;
209                            case 2:
210                                cout |= (cIdx << 1);
211                                break;
212                            case 3:
213                                cout |= (cIdx >> 4);
214                                out.write( cout );
215                                cout = (cIdx << 4) & 255;
216                                break;
217                            case 4:
218                                cout |= (cIdx >> 1);
219                                out.write( cout );
220                                cout = (cIdx << 7) & 255;
221                                break;
222                            case 5:
223                                cout |= cIdx << 2;
224                                break;
225                            case 6:
226                                cout |= (cIdx >> 3);
227                                out.write( cout );
228                                cout = (cIdx << 5) & 255;
229                                break;
230                            case 7:
231                                cout |= cIdx;
232                                out.write( cout );
233                                break;
234                        }
235                        mod = ( mod + 1 ) % 8;
236                    }
237                    else {
238                        return null;
239                    }
240                }
241            }
242            else {
243                b = false;
244            }
245        }
246
247        /*
248         * Padding.
249         */
250
251        switch ( mod ) {
252        case 1:
253            // In state 1 only 5 bits of the next 40 bit has been decoded.
254        case 3:
255            // In state 3 1 bit must have also been written in the next byte.
256        case 6:
257            // In state 6 2 bits must have also been written in the next byte.
258            return null;
259        default:
260            if ( bStrict ) {
261                while ( mod != 0 && idx < in.length() && in.charAt( idx ) == '=' ) {
262                    ++idx;
263                    mod = ( mod + 1 ) % 8;
264                }
265                if (mod != 0 || idx < in.length() ) {
266                    return null;
267                }
268            }
269            break;
270        }
271        return out.toByteArray();
272    }
273
274    /**
275     * Encodes a string.
276     * @param in unencoded text string.
277     * @return encoded string or null
278     */
279    public static String encodeString(String in) {
280        if (in == null) {
281            return null;
282        }
283        if (in.length() == 0) {
284            return "";
285        }
286
287        StringBuffer out = new StringBuffer( 256 );
288
289        boolean b = true;
290        int idx = 0;
291        int cin;
292        int cout = 0;
293        int mod = 0;
294
295        /*
296         * Loop.
297         */
298
299        while ( b ) {
300            if ( idx < in.length() ) {
301                cin = in.charAt( idx++ );
302                if ( cin < 256 ) {
303                    switch ( mod ) {
304                    case 0:
305                        cout = ( cin >> 3 ) & 31;
306                        out.append( encodeTab.charAt( cout ) );
307                        cout = ( cin << 2 ) & 31;
308                        break;
309                    case 1:
310                        cout |= ( cin >> 6 ) & 31;
311                        out.append( encodeTab.charAt( cout ) );
312                        cout = ( cin >> 1 ) & 31;
313                        out.append( encodeTab.charAt( cout ) );
314                        cout = ( cin << 4 ) & 31;
315                        break;
316                    case 2:
317                        cout |= ( cin >> 4 ) & 31;
318                        out.append( encodeTab.charAt( cout ) );
319                        cout = ( cin << 1 ) & 31;
320                        break;
321                    case 3:
322                        cout |= ( cin >> 7 ) & 31;
323                        out.append( encodeTab.charAt( cout ) );
324                        cout = ( cin >> 2 ) & 31;
325                        out.append( encodeTab.charAt( cout ) );
326                        cout = ( cin << 3 ) & 31;
327                        break;
328                    case 4:
329                        cout |= ( cin >> 5 ) & 31;
330                        out.append( encodeTab.charAt( cout ) );
331                        cout = cin & 31;
332                        out.append( encodeTab.charAt( cout ) );
333                        break;
334                    }
335                    mod = ( mod + 1 ) % 5;
336                }
337                else {
338                    return null;
339                }
340            }
341            else {
342                b = false;
343            }
344        }
345
346        /*
347         * Padding.
348         */
349
350        switch( mod ) {
351            case 0:
352                break;
353            case 1:
354                out.append( encodeTab.charAt( cout ) );
355                out.append( "======" );
356                break;
357            case 2:
358                out.append( encodeTab.charAt( cout ) );
359                out.append( "====" );
360                break;
361            case 3:
362                out.append( encodeTab.charAt( cout ) );
363                out.append( "===" );
364                break;
365            case 4:
366                out.append( encodeTab.charAt( cout ) );
367                out.append( "=" );
368                break;
369        }
370
371        return out.toString();
372    }
373
374    /**
375     * Encodes a byte array.
376     * @param in byte array.
377     * @return encoded string or null
378     */
379    public static String encodeArray(byte[] in) {
380        if (in == null) {
381            return null;
382        }
383        if (in.length == 0) {
384            return "";
385        }
386
387        StringBuffer out = new StringBuffer( 256 );
388
389        boolean b = true;
390        int idx = 0;
391        int cin;
392        int cout = 0;
393        int mod = 0;
394
395        /*
396         * Loop.
397         */
398
399        while ( b ) {
400            if ( idx < in.length ) {
401                cin = in[ idx++ ] & 255;
402                switch ( mod ) {
403                    case 0:
404                        cout = ( cin >> 3 ) & 31;
405                        out.append( encodeTab.charAt( cout ) );
406                        cout = ( cin << 2 ) & 31;
407                        break;
408                    case 1:
409                        cout |= ( cin >> 6 ) & 31;
410                        out.append( encodeTab.charAt( cout ) );
411                        cout = ( cin >> 1 ) & 31;
412                        out.append( encodeTab.charAt( cout ) );
413                        cout = ( cin << 4 ) & 31;
414                        break;
415                    case 2:
416                        cout |= ( cin >> 4 ) & 31;
417                        out.append( encodeTab.charAt( cout ) );
418                        cout = ( cin << 1 ) & 31;
419                        break;
420                    case 3:
421                        cout |= ( cin >> 7 ) & 31;
422                        out.append( encodeTab.charAt( cout ) );
423                        cout = ( cin >> 2 ) & 31;
424                        out.append( encodeTab.charAt( cout ) );
425                        cout = ( cin << 3 ) & 31;
426                        break;
427                    case 4:
428                        cout |= ( cin >> 5 ) & 31;
429                        out.append( encodeTab.charAt( cout ) );
430                        cout = cin & 31;
431                        out.append( encodeTab.charAt( cout ) );
432                        break;
433                }
434                mod = ( mod + 1 ) % 5;
435            }
436            else {
437                b = false;
438            }
439        }
440
441        /*
442         * Padding.
443         */
444
445        switch( mod ) {
446            case 0:
447                break;
448            case 1:
449                out.append( encodeTab.charAt( cout ) );
450                out.append( "======" );
451                break;
452            case 2:
453                out.append( encodeTab.charAt( cout ) );
454                out.append( "====" );
455                break;
456            case 3:
457                out.append( encodeTab.charAt( cout ) );
458                out.append( "===" );
459                break;
460            case 4:
461                out.append( encodeTab.charAt( cout ) );
462                out.append( "=" );
463                break;
464        }
465
466        return out.toString();
467    }
468
469}