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 * 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 28 package com.google.polo.wire.json; 29 30 import 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 */ 36 public 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 176