17c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/* 27c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Licensed to the Apache Software Foundation (ASF) under one or more 37c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * contributor license agreements. See the NOTICE file distributed with 47c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * this work for additional information regarding copyright ownership. 57c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * The ASF licenses this file to You under the Apache License, Version 2.0 67c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * (the "License"); you may not use this file except in compliance with 77c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * the License. You may obtain a copy of the License at 87c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * 97c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * http://www.apache.org/licenses/LICENSE-2.0 107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * 117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Unless required by applicable law or agreed to in writing, software 127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * distributed under the License is distributed on an "AS IS" BASIS, 137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * See the License for the specific language governing permissions and 157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * limitations under the License. 167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */ 177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/* 197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * NOTE: This class copied from the Android Open Source Project: 207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * dalvik/libcore/luni/src/main/java/org/apache/harmony/luni/util/Base64.java 217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */ 227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/** 247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet* @author Alexander Y. Kleymenov 257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet* @version $Revision$ 267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet*/ 277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetpackage com.google.polo.wire.json; 297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.io.UnsupportedEncodingException; 317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/** 337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * This class implements Base64 encoding/decoding functionality 347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * as specified in RFC 2045 (http://www.ietf.org/rfc/rfc2045.txt). 357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */ 367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetpublic class Base64 { 377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet public static byte[] decode(byte[] in) { 397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet return decode(in, in.length); 407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet public static byte[] decode(byte[] in, int len) { 437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // approximate output length 447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet int length = len / 4 * 3; 457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // return an empty array on emtpy or short input without padding 467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet if (length == 0) { 477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet return new byte[0]; 487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // temporary array 507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet byte[] out = new byte[length]; 517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // number of padding characters ('=') 527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet int pad = 0; 537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet byte chr; 547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // compute the number of the padding characters 557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // and adjust the length of the input 567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet for (;;len--) { 577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet chr = in[len-1]; 587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // skip the neutral characters 597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet if ((chr == '\n') || (chr == '\r') || 607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet (chr == ' ') || (chr == '\t')) { 617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet continue; 627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet if (chr == '=') { 647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet pad++; 657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } else { 667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet break; 677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // index in the output array 707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet int out_index = 0; 717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // index in the input array 727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet int in_index = 0; 737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // holds the value of the input character 747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet int bits = 0; 757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // holds the value of the input quantum 767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet int quantum = 0; 777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet for (int i=0; i<len; i++) { 787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet chr = in[i]; 797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // skip the neutral characters 807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet if ((chr == '\n') || (chr == '\r') || 817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet (chr == ' ') || (chr == '\t')) { 827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet continue; 837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet if ((chr >= 'A') && (chr <= 'Z')) { 857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // char ASCII value 867c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // A 65 0 877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // Z 90 25 (ASCII - 65) 887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet bits = chr - 65; 897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } else if ((chr >= 'a') && (chr <= 'z')) { 907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // char ASCII value 917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // a 97 26 927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // z 122 51 (ASCII - 71) 937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet bits = chr - 71; 947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } else if ((chr >= '0') && (chr <= '9')) { 957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // char ASCII value 967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // 0 48 52 977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // 9 57 61 (ASCII + 4) 987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet bits = chr + 4; 997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } else if (chr == '+') { 1007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet bits = 62; 1017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } else if (chr == '/') { 1027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet bits = 63; 1037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } else { 1047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet return null; 1057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 1067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // append the value to the quantum 1077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet quantum = (quantum << 6) | (byte) bits; 1087c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet if (in_index%4 == 3) { 1097c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // 4 characters were read, so make the output: 1107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[out_index++] = (byte) ((quantum & 0x00FF0000) >> 16); 1117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[out_index++] = (byte) ((quantum & 0x0000FF00) >> 8); 1127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[out_index++] = (byte) (quantum & 0x000000FF); 1137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 1147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet in_index++; 1157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 1167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet if (pad > 0) { 1177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // adjust the quantum value according to the padding 1187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet quantum = quantum << (6*pad); 1197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // make output 1207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[out_index++] = (byte) ((quantum & 0x00FF0000) >> 16); 1217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet if (pad == 1) { 1227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[out_index++] = (byte) ((quantum & 0x0000FF00) >> 8); 1237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 1247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 1257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet // create the resulting array 1267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet byte[] result = new byte[out_index]; 1277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet System.arraycopy(out, 0, result, 0, out_index); 1287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet return result; 1297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 1307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 1317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet private static final byte[] map = new byte[] 1327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 1337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 1347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 1357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', 1367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet '4', '5', '6', '7', '8', '9', '+', '/'}; 1377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 1387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet public static String encode(byte[] in, String charsetName) throws UnsupportedEncodingException { 1397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet int length = in.length * 4 / 3; 1407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet length += length / 76 + 3; // for crlr 1417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet byte[] out = new byte[length]; 1427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet int index = 0, i, crlr = 0, end = in.length - in.length%3; 1437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet for (i=0; i<end; i+=3) { 1447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = map[(in[i] & 0xff) >> 2]; 1457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = map[((in[i] & 0x03) << 4) 1467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet | ((in[i+1] & 0xff) >> 4)]; 1477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = map[((in[i+1] & 0x0f) << 2) 1487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet | ((in[i+2] & 0xff) >> 6)]; 1497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = map[(in[i+2] & 0x3f)]; 1507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet if (((index - crlr)%76 == 0) && (index != 0)) { 1517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = '\n'; 1527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet crlr++; 1537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet //out[index++] = '\r'; 1547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet //crlr++; 1557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 1567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 1577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet switch (in.length % 3) { 1587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet case 1: 1597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = map[(in[end] & 0xff) >> 2]; 1607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = map[(in[end] & 0x03) << 4]; 1617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = '='; 1627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = '='; 1637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet break; 1647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet case 2: 1657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = map[(in[end] & 0xff) >> 2]; 1667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = map[((in[end] & 0x03) << 4) 1677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet | ((in[end+1] & 0xff) >> 4)]; 1687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = map[((in[end+1] & 0x0f) << 2)]; 1697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet out[index++] = '='; 1707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet break; 1717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 1727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet return new String(out, 0, index, charsetName); 1737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet } 1747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet} 1757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet 176