Base64.java revision f33eae7e84eb6d3b0f4e86b59605bb3de73009f3
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @author Alexander Y. Kleymenov
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*/
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.luni.util;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.UnsupportedEncodingException;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This class implements Base64 encoding/decoding functionality
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * as specified in RFC 2045 (http://www.ietf.org/rfc/rfc2045.txt).
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class Base64 {
31f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static byte[] decode(byte[] in) {
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return decode(in, in.length);
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
35f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static byte[] decode(byte[] in, int len) {
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // approximate output length
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length = len / 4 * 3;
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // return an empty array on emtpy or short input without padding
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (length == 0) {
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return new byte[0];
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // temporary array
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] out = new byte[length];
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // number of padding characters ('=')
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int pad = 0;
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte chr;
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // compute the number of the padding characters
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // and adjust the length of the input
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (;;len--) {
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            chr = in[len-1];
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // skip the neutral characters
53f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            if ((chr == '\n') || (chr == '\r') ||
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    (chr == ' ') || (chr == '\t')) {
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                continue;
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (chr == '=') {
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                pad++;
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // index in the output array
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int out_index = 0;
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // index in the input array
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int in_index = 0;
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // holds the value of the input character
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int bits = 0;
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // holds the value of the input quantum
70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int quantum = 0;
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (int i=0; i<len; i++) {
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            chr = in[i];
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // skip the neutral characters
74f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            if ((chr == '\n') || (chr == '\r') ||
75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    (chr == ' ') || (chr == '\t')) {
76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                continue;
77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if ((chr >= 'A') && (chr <= 'Z')) {
79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // char ASCII value
80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                //  A    65    0
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                //  Z    90    25 (ASCII - 65)
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                bits = chr - 65;
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if ((chr >= 'a') && (chr <= 'z')) {
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // char ASCII value
85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                //  a    97    26
86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                //  z    122   51 (ASCII - 71)
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                bits = chr - 71;
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if ((chr >= '0') && (chr <= '9')) {
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // char ASCII value
90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                //  0    48    52
91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                //  9    57    61 (ASCII + 4)
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                bits = chr + 4;
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (chr == '+') {
94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                bits = 62;
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else if (chr == '/') {
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                bits = 63;
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return null;
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // append the value to the quantum
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            quantum = (quantum << 6) | (byte) bits;
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (in_index%4 == 3) {
103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // 4 characters were read, so make the output:
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[out_index++] = (byte) ((quantum & 0x00FF0000) >> 16);
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[out_index++] = (byte) ((quantum & 0x0000FF00) >> 8);
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[out_index++] = (byte) (quantum & 0x000000FF);
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            in_index++;
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (pad > 0) {
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // adjust the quantum value according to the padding
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            quantum = quantum << (6*pad);
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // make output
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            out[out_index++] = (byte) ((quantum & 0x00FF0000) >> 16);
115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (pad == 1) {
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[out_index++] = (byte) ((quantum & 0x0000FF00) >> 8);
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // create the resulting array
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] result = new byte[out_index];
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        System.arraycopy(out, 0, result, 0, out_index);
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final byte[] map = new byte[]
126f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
127f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
128f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
129f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes         'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         '4', '5', '6', '7', '8', '9', '+', '/'};
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static String encode(byte[] in, String charsetName) throws UnsupportedEncodingException {
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length = in.length * 4 / 3;
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        length += length / 76 + 3; // for crlr
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        byte[] out = new byte[length];
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int index = 0, i, crlr = 0, end = in.length - in.length%3;
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        for (i=0; i<end; i+=3) {
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            out[index++] = map[(in[i] & 0xff) >> 2];
139f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            out[index++] = map[((in[i] & 0x03) << 4)
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                | ((in[i+1] & 0xff) >> 4)];
141f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes            out[index++] = map[((in[i+1] & 0x0f) << 2)
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                | ((in[i+2] & 0xff) >> 6)];
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            out[index++] = map[(in[i+2] & 0x3f)];
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (((index - crlr)%76 == 0) && (index != 0)) {
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[index++] = '\n';
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                crlr++;
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                //out[index++] = '\r';
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                //crlr++;
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        switch (in.length % 3) {
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case 1:
153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[index++] = map[(in[end] & 0xff) >> 2];
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[index++] = map[(in[end] & 0x03) << 4];
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[index++] = '=';
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[index++] = '=';
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            case 2:
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[index++] = map[(in[end] & 0xff) >> 2];
160f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                out[index++] = map[((in[end] & 0x03) << 4)
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                                    | ((in[end+1] & 0xff) >> 4)];
162f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes                out[index++] = map[((in[end+1] & 0x0f) << 2)];
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                out[index++] = '=';
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                break;
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new String(out, 0, index, charsetName);
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
170