blob: 2fdadc59d68a83d974601ae293bb833839f46e0d [file] [log] [blame]
Jerome Poichet7c997852014-05-20 10:50:05 -07001/*
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 * NOTE: This class copied from the Android Open Source Project:
20 * dalvik/libcore/luni/src/main/java/org/apache/harmony/luni/util/Base64.java
21 */
22
23/**
24* @author Alexander Y. Kleymenov
25* @version $Revision$
26*/
27
28package com.google.polo.wire.json;
29
30import java.io.UnsupportedEncodingException;
31
32/**
33 * This class implements Base64 encoding/decoding functionality
34 * as specified in RFC 2045 (http://www.ietf.org/rfc/rfc2045.txt).
35 */
36public class Base64 {
37
38 public static byte[] decode(byte[] in) {
39 return decode(in, in.length);
40 }
41
42 public static byte[] decode(byte[] in, int len) {
43 // approximate output length
44 int length = len / 4 * 3;
45 // return an empty array on emtpy or short input without padding
46 if (length == 0) {
47 return new byte[0];
48 }
49 // temporary array
50 byte[] out = new byte[length];
51 // number of padding characters ('=')
52 int pad = 0;
53 byte chr;
54 // compute the number of the padding characters
55 // and adjust the length of the input
56 for (;;len--) {
57 chr = in[len-1];
58 // skip the neutral characters
59 if ((chr == '\n') || (chr == '\r') ||
60 (chr == ' ') || (chr == '\t')) {
61 continue;
62 }
63 if (chr == '=') {
64 pad++;
65 } else {
66 break;
67 }
68 }
69 // index in the output array
70 int out_index = 0;
71 // index in the input array
72 int in_index = 0;
73 // holds the value of the input character
74 int bits = 0;
75 // holds the value of the input quantum
76 int quantum = 0;
77 for (int i=0; i<len; i++) {
78 chr = in[i];
79 // skip the neutral characters
80 if ((chr == '\n') || (chr == '\r') ||
81 (chr == ' ') || (chr == '\t')) {
82 continue;
83 }
84 if ((chr >= 'A') && (chr <= 'Z')) {
85 // char ASCII value
86 // A 65 0
87 // Z 90 25 (ASCII - 65)
88 bits = chr - 65;
89 } else if ((chr >= 'a') && (chr <= 'z')) {
90 // char ASCII value
91 // a 97 26
92 // z 122 51 (ASCII - 71)
93 bits = chr - 71;
94 } else if ((chr >= '0') && (chr <= '9')) {
95 // char ASCII value
96 // 0 48 52
97 // 9 57 61 (ASCII + 4)
98 bits = chr + 4;
99 } else if (chr == '+') {
100 bits = 62;
101 } else if (chr == '/') {
102 bits = 63;
103 } else {
104 return null;
105 }
106 // append the value to the quantum
107 quantum = (quantum << 6) | (byte) bits;
108 if (in_index%4 == 3) {
109 // 4 characters were read, so make the output:
110 out[out_index++] = (byte) ((quantum & 0x00FF0000) >> 16);
111 out[out_index++] = (byte) ((quantum & 0x0000FF00) >> 8);
112 out[out_index++] = (byte) (quantum & 0x000000FF);
113 }
114 in_index++;
115 }
116 if (pad > 0) {
117 // adjust the quantum value according to the padding
118 quantum = quantum << (6*pad);
119 // make output
120 out[out_index++] = (byte) ((quantum & 0x00FF0000) >> 16);
121 if (pad == 1) {
122 out[out_index++] = (byte) ((quantum & 0x0000FF00) >> 8);
123 }
124 }
125 // create the resulting array
126 byte[] result = new byte[out_index];
127 System.arraycopy(out, 0, result, 0, out_index);
128 return result;
129 }
130
131 private static final byte[] map = new byte[]
132 {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
133 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
134 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
135 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
136 '4', '5', '6', '7', '8', '9', '+', '/'};
137
138 public static String encode(byte[] in, String charsetName) throws UnsupportedEncodingException {
139 int length = in.length * 4 / 3;
140 length += length / 76 + 3; // for crlr
141 byte[] out = new byte[length];
142 int index = 0, i, crlr = 0, end = in.length - in.length%3;
143 for (i=0; i<end; i+=3) {
144 out[index++] = map[(in[i] & 0xff) >> 2];
145 out[index++] = map[((in[i] & 0x03) << 4)
146 | ((in[i+1] & 0xff) >> 4)];
147 out[index++] = map[((in[i+1] & 0x0f) << 2)
148 | ((in[i+2] & 0xff) >> 6)];
149 out[index++] = map[(in[i+2] & 0x3f)];
150 if (((index - crlr)%76 == 0) && (index != 0)) {
151 out[index++] = '\n';
152 crlr++;
153 //out[index++] = '\r';
154 //crlr++;
155 }
156 }
157 switch (in.length % 3) {
158 case 1:
159 out[index++] = map[(in[end] & 0xff) >> 2];
160 out[index++] = map[(in[end] & 0x03) << 4];
161 out[index++] = '=';
162 out[index++] = '=';
163 break;
164 case 2:
165 out[index++] = map[(in[end] & 0xff) >> 2];
166 out[index++] = map[((in[end] & 0x03) << 4)
167 | ((in[end+1] & 0xff) >> 4)];
168 out[index++] = map[((in[end+1] & 0x0f) << 2)];
169 out[index++] = '=';
170 break;
171 }
172 return new String(out, 0, index, charsetName);
173 }
174}
175