/* See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * Esri Inc. licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.esri.gpt.framework.security.codec; import com.esri.gpt.framework.util.Val; import java.io.IOException; import java.io.UnsupportedEncodingException; /** * Handles base64 encoding/decoding. */ public class Base64 { // class variables ============================================================= private static byte[] BASE64_DEC_MAP; private static byte[] BASE64_ENC_MAP; // instance variables ========================================================== /** * Static initialization */ static { // rfc-2045: Base64 Alphabet byte[] map = { (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' }; BASE64_ENC_MAP = map; BASE64_DEC_MAP = new byte[128]; for (int i=0;i<BASE64_ENC_MAP.length;i++) { BASE64_DEC_MAP[BASE64_ENC_MAP[i]] = (byte)i; } } // constructors ================================================================ /** Default constructor. */ private Base64() {} // properties ================================================================== // methods ===================================================================== /** * This method encodes the given byte array using the base64 encoding * specified in RFC-2045 (Section 6.8). * @param data the data to encode * @return the base64 encoded data */ private final static byte[] encode(byte[] data) { if (data == null) { return null; } int sidx, didx; byte dest[] = new byte[((data.length+2)/3)*4]; // 3-byte to 4-byte conversion + 0-63 to ascii printable conversion for (sidx=0, didx=0; sidx < data.length-2; sidx += 3) { dest[didx++] = BASE64_ENC_MAP[(data[sidx] >>> 2) & 077]; dest[didx++] = BASE64_ENC_MAP[(data[sidx+1] >>> 4) & 017 | (data[sidx] << 4) & 077]; dest[didx++] = BASE64_ENC_MAP[(data[sidx+2] >>> 6) & 003 | (data[sidx+1] << 2) & 077]; dest[didx++] = BASE64_ENC_MAP[data[sidx+2] & 077]; } if (sidx < data.length) { dest[didx++] = BASE64_ENC_MAP[(data[sidx] >>> 2) & 077]; if (sidx < data.length-1) { dest[didx++] = BASE64_ENC_MAP[(data[sidx+1] >>> 4) & 017 | (data[sidx] << 4) & 077]; dest[didx++] = BASE64_ENC_MAP[(data[sidx+1] << 2) & 077]; } else { dest[didx++] = BASE64_ENC_MAP[(data[sidx] << 4) & 077]; } } // add padding for ( ; didx < dest.length; didx++) { dest[didx] = (byte) '='; } return dest; } /** * This method encodes the given string using the base64 encoding * specified in RFC-2045 (Section 6.8). It's used for example in the * "Basic" authorization scheme. * @param data the string to encode * @param charset the character set (if not supplied UTF-8 will be used) * @return the base64 encoded string * @throws UnsupportedEncodingException if the exception occurs */ public final static String encode(String data, String charset) throws UnsupportedEncodingException { if (data == null) { return null; } else if (data.length() == 0) { return ""; } charset = Val.chkStr(charset); if (charset.length() == 0) charset= "UTF-8"; byte[] aData = data.getBytes(charset); //String sEncoded = new String(encode(aData),charset); String sEncoded = (new sun.misc.BASE64Encoder()).encode(aData); return sEncoded; } /** * This method decodes the given byte array using the base64 encoding * specified in RFC-2045 (Section 6.8). * @param data the base64 encoded data. * @return the decoded data. */ private final static byte[] decode(byte[] data) { if (data == null) { return null; } int tail = data.length; while (data[tail-1] == '=') tail--; byte dest[] = new byte[tail - data.length/4]; // ascii printable to 0-63 conversion for (int idx = 0; idx <data.length; idx++) { data[idx] = BASE64_DEC_MAP[data[idx]]; } // 4-byte to 3-byte conversion int sidx, didx; for (sidx = 0, didx=0; didx < dest.length-2; sidx += 4, didx += 3) { dest[didx] = (byte)( ((data[sidx] << 2) & 255) | ((data[sidx+1] >>> 4) & 003) ); dest[didx+1] = (byte) ( ((data[sidx+1] << 4) & 255) | ((data[sidx+2] >>> 2) & 017) ); dest[didx+2] = (byte) ( ((data[sidx+2] << 6) & 255) | (data[sidx+3] & 077) ); } if (didx < dest.length) { dest[didx] = (byte) ( ((data[sidx] << 2) & 255) | ((data[sidx+1] >>> 4) & 003) ); } if (++didx < dest.length) { dest[didx] = (byte) ( ((data[sidx+1] << 4) & 255) | ((data[sidx+2] >>> 2) & 017) ); } return dest; } /** * This method decodes the given string using the base64 encoding * specified in RFC-2045 (Section 6.8). * @param data the base64 encoded string. * @param charset the character set (if not supplied UTF-8 will be used) * @return the decoded string * @throws IOException */ public final static String decode(String data, String charset) throws IOException { if (data == null) { return null; } else if (data.length() == 0) { return ""; } charset = Val.chkStr(charset); if (charset.length() == 0) charset= "UTF-8"; //byte[] aData = data.getBytes(charset); //String = new String(decode(aData),charset); byte[] aData = (new sun.misc.BASE64Decoder()).decodeBuffer(data); String sDecoded = new String(aData,charset); return sDecoded; } }