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