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