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