1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2007 Esmertec AG.
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2007 The Android Open Source Project
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage android.support.v7.mms.pdu;
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class Base64 {
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Used to get the number of Quadruples.
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static final int FOURBYTE = 4;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Byte used to pad output.
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static final byte PAD = (byte) '=';
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * The base length.
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static final int BASELENGTH = 255;
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Create arrays to hold the base64 characters
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static byte[] base64Alphabet = new byte[BASELENGTH];
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Populating the character arrays
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static {
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0; i < BASELENGTH; i++) {
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            base64Alphabet[i] = (byte) -1;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 'Z'; i >= 'A'; i--) {
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            base64Alphabet[i] = (byte) (i - 'A');
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 'z'; i >= 'a'; i--) {
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            base64Alphabet[i] = (byte) (i - 'a' + 26);
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = '9'; i >= '0'; i--) {
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            base64Alphabet[i] = (byte) (i - '0' + 52);
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        base64Alphabet['+'] = 62;
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        base64Alphabet['/'] = 63;
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Decodes Base64 data into octects
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param base64Data Byte array containing Base64 data
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return Array containing decoded data.
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static byte[] decodeBase64(byte[] base64Data) {
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // RFC 2045 requires that we discard ALL non-Base64 characters
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        base64Data = discardNonBase64(base64Data);
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // handle the edge case, so we don't have to worry about it later
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (base64Data.length == 0) {
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return new byte[0];
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int numberQuadruple = base64Data.length / FOURBYTE;
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        byte decodedData[] = null;
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Throw away anything not in base64Data
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int encodedIndex = 0;
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int dataIndex = 0;
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        {
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // this sizes the output array properly - rlw
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            int lastData = base64Data.length;
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // ignore the '=' padding
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            while (base64Data[lastData - 1] == PAD) {
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (--lastData == 0) {
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    return new byte[0];
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            decodedData = new byte[lastData - numberQuadruple];
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0; i < numberQuadruple; i++) {
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            dataIndex = i * 4;
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            marker0 = base64Data[dataIndex + 2];
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            marker1 = base64Data[dataIndex + 3];
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            b1 = base64Alphabet[base64Data[dataIndex]];
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            b2 = base64Alphabet[base64Data[dataIndex + 1]];
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (marker0 != PAD && marker1 != PAD) {
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                //No PAD e.g 3cQl
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                b3 = base64Alphabet[marker0];
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                b4 = base64Alphabet[marker1];
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                decodedData[encodedIndex + 1] =
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else if (marker0 == PAD) {
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                //Two PAD e.g. 3c[Pad][Pad]
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else if (marker1 == PAD) {
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                //One PAD e.g. 3cQ[Pad]
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                b3 = base64Alphabet[marker0];
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                decodedData[encodedIndex + 1] =
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            encodedIndex += 3;
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return decodedData;
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Check octect wheter it is a base64 encoding.
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param octect to be checked byte
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return ture if it is base64 encoding, false otherwise.
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean isBase64(byte octect) {
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (octect == PAD) {
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return true;
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else if (base64Alphabet[octect] == -1) {
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return false;
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return true;
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Discards any characters outside of the base64 alphabet, per
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * the requirements on page 25 of RFC 2045 - "Any characters
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * outside of the base64 alphabet are to be ignored in base64
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * encoded data."
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param data The base-64 encoded data to groom
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return The data, less non-base64 characters (see RFC 2045).
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static byte[] discardNonBase64(byte[] data) {
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        byte groomedData[] = new byte[data.length];
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int bytesCopied = 0;
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0; i < data.length; i++) {
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (isBase64(data[i])) {
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                groomedData[bytesCopied++] = data[i];
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        byte packedData[] = new byte[bytesCopied];
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return packedData;
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
168