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