196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/* ====================================================================
296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Copyright (c) 2006 J.T. Beetstra
396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Permission is hereby granted, free of charge, to any person obtaining
596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * a copy of this software and associated documentation files (the
696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * "Software"), to deal in the Software without restriction, including
796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * without limitation the rights to use, copy, modify, merge, publish,
896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * distribute, sublicense, and/or sell copies of the Software, and to
996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * permit persons to whom the Software is furnished to do so, subject to
1096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * the following conditions:
1196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
1296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * The above copyright notice and this permission notice shall be
1396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * included in all copies or substantial portions of the Software.
1496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
1596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * ====================================================================
2396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
2496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
2596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectpackage com.beetstra.jutf7;
2696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
2796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectimport java.util.Arrays;
2896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
2996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project/**
3096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * <p>
3196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Represent a base 64 mapping. The 64 characters used in the encoding can be
3296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * specified, since modified-UTF-7 uses other characters than UTF-7 (',' instead
3396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * of '/').
3496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * </p>
3596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * <p>
3696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * The exact type of the arguments and result values is adapted to the needs of
3796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * the encoder and decoder, as opposed to following a strict interpretation of
3896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * base 64.
3996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * </p>
4096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * <p>
4196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * Base 64, as specified in RFC 2045, is an encoding used to encode bytes as
4296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * characters. In (modified-)UTF-7 however, it is used to encode characters as
4396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * bytes, using some intermediate steps:
4496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * </p>
4596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * <ol>
4696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * <li>Encode all characters as a 16-bit (UTF-16) integer value</li>
4796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * <li>Write this as stream of bytes (most-significant first)</li>
4896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * <li>Encode these bytes using (modified) base 64 encoding</li>
4996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * <li>Write the thus formed stream of characters as a stream of bytes, using
5096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * ASCII encoding</li>
5196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * </ol>
5296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project *
5396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project * @author Jaap Beetstra
5496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project */
5596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Projectclass Base64Util {
5696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private static final int ALPHABET_LENGTH = 64;
5796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private final char[] alphabet;
5896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    private final int[] inverseAlphabet;
5996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
6096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
6196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Initializes the class with the specified encoding/decoding alphabet.
6296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     *
6396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @param alphabet
6496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @throws IllegalArgumentException if alphabet is not 64 characters long or
6596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     *             contains characters which are not 7-bit ASCII
6696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
6796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    Base64Util(final String alphabet) {
6896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        this.alphabet = alphabet.toCharArray();
6996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (alphabet.length() != ALPHABET_LENGTH)
7096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            throw new IllegalArgumentException("alphabet has incorrect length (should be 64, not "
7196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                    + alphabet.length() + ")");
7296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        inverseAlphabet = new int[128];
7396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        Arrays.fill(inverseAlphabet, -1);
7496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        for (int i = 0; i < this.alphabet.length; i++) {
7596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            final char ch = this.alphabet[i];
7696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            if (ch >= 128)
7796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project                throw new IllegalArgumentException("invalid character in alphabet: " + ch);
7896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            inverseAlphabet[ch] = i;
7996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        }
8096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
8196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
8296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
8396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Returns the integer value of the six bits represented by the specified
8496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * character.
8596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     *
8696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @param ch The character, as a ASCII encoded byte
8796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @return The six bits, as an integer value, or -1 if the byte is not in
8896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     *         the alphabet
8996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
9096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    int getSextet(final byte ch) {
9196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (ch >= 128)
9296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return -1;
9396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return inverseAlphabet[ch];
9496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
9596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
9696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
9796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Tells whether the alphabet contains the specified character.
9896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     *
9996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @param ch The character
10096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @return true if the alphabet contains <code>ch</code>, false otherwise
10196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
10296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    boolean contains(final char ch) {
10396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        if (ch >= 128)
10496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project            return false;
10596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return inverseAlphabet[ch] >= 0;
10696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
10796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project
10896c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    /**
10996c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * Encodes the six bit group as a character.
11096c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     *
11196c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @param sextet The six bit group to be encoded
11296c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     * @return The ASCII value of the character
11396c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project     */
11496c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    byte getChar(final int sextet) {
11596c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project        return (byte)alphabet[sextet];
11696c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project    }
11796c5af40d639d629267794f4f0338a267ff94ce5The Android Open Source Project}
118