Return-Path: Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: (qmail 7510 invoked from network); 29 Jun 2009 19:35:11 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 29 Jun 2009 19:35:11 -0000 Received: (qmail 13384 invoked by uid 500); 29 Jun 2009 19:35:21 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 13296 invoked by uid 500); 29 Jun 2009 19:35:21 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 13287 invoked by uid 99); 29 Jun 2009 19:35:21 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 29 Jun 2009 19:35:21 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 29 Jun 2009 19:35:19 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 2433923888E7; Mon, 29 Jun 2009 19:34:59 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r789418 - /commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/util/Base64.java Date: Mon, 29 Jun 2009 19:34:59 -0000 To: commits@commons.apache.org From: mturk@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090629193459.2433923888E7@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: mturk Date: Mon Jun 29 19:34:58 2009 New Revision: 789418 URL: http://svn.apache.org/viewvc?rev=789418&view=rev Log: Add full Base64 decode/encode Added: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/util/Base64.java (with props) Added: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/util/Base64.java URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/util/Base64.java?rev=789418&view=auto ============================================================================== --- commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/util/Base64.java (added) +++ commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/util/Base64.java Mon Jun 29 19:34:58 2009 @@ -0,0 +1,323 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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 org.apache.commons.runtime.util; + +import java.io.UnsupportedEncodingException; + +/** + * Base64 encoding enumeration + * + * @author Mladen Turk + * + */ +public class Base64 +{ + + private Base64() + { + // Disable creation + } + + /** + * Wrap encoded lines after {@code COLS} character {@code (default 72)}. + */ + public static final int COLS = 72; + private static final char padding = '='; + private static final char[] basis64 = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' + }; + + // ASCII table + private static final byte[] pr2six = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }; + + /** + * Calculate number of bytes needed to {@code Base64} encode + * the {@code src} array. + * + * @param src byte array to encode. + * @param srcPos offset from the start of the {@code data} byte array. + * @param len length in the {@code src} byte array. + * @param wrap Wrap encoded lines after {@code wrap} character. + * Use {@code 0} to disable line wrapping. + * + * @return length needed to {@code Base64} encode the array. + */ + public static int encodeLength(byte[] src, int srcPos, int len, + int wrap) + { + int dstlen; + + dstlen = (((len + 2) / 3) * 4); + if (wrap == -1) + wrap = COLS; + if (wrap > 0) + dstlen += (dstlen / wrap); + + return dstlen; + } + + public static int encode(byte[] src, int srcPos, byte[] dst, + int dstPos, int len, int wrap) + throws IndexOutOfBoundsException, NullPointerException + { + int oc = 0; + int dp = dstPos; + int sc = srcPos; + int dl = dst.length; + int i; + int[] inp = new int[3]; + int[] out = new int[4]; + + if (wrap == -1) + wrap = COLS; + while (len >= 3) { + inp[0] = (int)src[sc++] & 0xFF; + inp[1] = (int)src[sc++] & 0xFF; + inp[2] = (int)src[sc++] & 0xFF; + len -= 3; + + out[0] = ((inp[0] >> 2)); + out[1] = ((inp[0] & 0x03) << 4) + (inp[1] >> 4); + out[2] = ((inp[1] & 0x0F) << 2) + (inp[2] >> 6); + out[3] = ((inp[2] & 0x3F)); + + if (dp + 4 > dl) + throw new IndexOutOfBoundsException("Destination is too small"); + dst[dp++] = (byte)basis64[out[0]]; + dst[dp++] = (byte)basis64[out[1]]; + dst[dp++] = (byte)basis64[out[2]]; + dst[dp++] = (byte)basis64[out[3]]; + if (wrap > 0) { + if (++oc % (wrap / 4) == 0) + dst[dp++] = '\n'; + } + } + // Pad with remaining 1 or 2 bytes + if (len != 0) { + inp[0] = inp[1] = inp[2] = 0; + for (i = 0; i < len; i++) + inp[i] = (int)src[sc++] & 0xFF; + + out[0] = ((inp[0] >> 2)); + out[1] = ((inp[0] & 0x03) << 4) + (inp[1] >> 4); + out[2] = ((inp[1] & 0x0F) << 2) + (inp[2] >> 6); + + if (dp + 4 > dl) + throw new IndexOutOfBoundsException("Destination is too small"); + dst[dp++] = (byte)basis64[out[0]]; + dst[dp++] = (byte)basis64[out[1]]; + if (len == 1) + dst[dp++] = padding; + else + dst[dp++] = (byte)basis64[out[2]]; + dst[dp++] = padding; + } + return dp - dstPos; + } + + public static int encode(byte[] src, int srcPos, char[] dst, + int dstPos, int len, int wrap) + throws IndexOutOfBoundsException, NullPointerException + { + int oc = 0; + int dp = dstPos; + int sc = srcPos; + int dl = dst.length; + int i; + int[] inp = new int[3]; + int[] out = new int[4]; + + if (wrap == -1) + wrap = COLS; + while (len >= 3) { + inp[0] = (int)src[sc++] & 0xFF; + inp[1] = (int)src[sc++] & 0xFF; + inp[2] = (int)src[sc++] & 0xFF; + len -= 3; + + out[0] = ((inp[0] >> 2)); + out[1] = ((inp[0] & 0x03) << 4) + (inp[1] >> 4); + out[2] = ((inp[1] & 0x0F) << 2) + (inp[2] >> 6); + out[3] = ((inp[2] & 0x3F)); + + if (dp + 4 > dl) + throw new IndexOutOfBoundsException("Destination is too small"); + dst[dp++] = basis64[out[0]]; + dst[dp++] = basis64[out[1]]; + dst[dp++] = basis64[out[2]]; + dst[dp++] = basis64[out[3]]; + if (wrap > 0) { + if (++oc % (wrap / 4) == 0) + dst[dp++] = '\n'; + } + } + // Pad with remaining 1 or 2 bytes + if (len != 0) { + inp[0] = inp[1] = inp[2] = 0; + for (i = 0; i < len; i++) + inp[i] = (int)src[sc++] & 0xFF; + + out[0] = ((inp[0] >> 2)); + out[1] = ((inp[0] & 0x03) << 4) + (inp[1] >> 4); + out[2] = ((inp[1] & 0x0F) << 2) + (inp[2] >> 6); + + if (dp + 4 > dl) + throw new IndexOutOfBoundsException("Destination is too small"); + dst[dp++] = basis64[out[0]]; + dst[dp++] = basis64[out[1]]; + if (len == 1) + dst[dp++] = padding; + else + dst[dp++] = basis64[out[2]]; + dst[dp++] = padding; + } + return dp - dstPos; + } + + /** + * Encode String using Base64 encoding. + *

+ * Input string is encoded from the {@code ISO 8859-1} charset. + *

+ * + * @param string String to encode. + * @param wrap Wrap encoded lines after {@code wrap} character. + * Use {@code 0} to disable line wrapping. + * @return {@code base64} encoded String. + */ + public static String encode(String string, int wrap) + { + try { + byte [] data = string.getBytes("8859_1"); + char [] dest = new char[encodeLength(data, 0, data.length, 0)]; + + int nencoded = encode(data, 0, dest, 0, data.length, 0); + return new String(dest, 0, nencoded); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + + /** + * Encode String using Base64 encoding. + *

+ * Input string is encoded from the {@code ISO 8859-1} charset + * and wrapped on {@code COLS} characters. + *

+ * + * @param string String to encode. + * @return {@code base64} encoded String. + */ + public static String encode(String string) + { + return encode(string, COLS); + } + + /** + * Calculate number of bytes needed to {@code Base64} decode + * the {@code src} array. + * + * @param src byte array to decode. + * @param srcPos offset from the start of the {@code data} byte array. + * @param len length in the {@code src} byte array. + * + * @return length needed to {@code Base64} decode the array. + */ + public static int decodeLength(byte[] src, int srcPos, int len) + { + int sc = 0; + int nprbytes; + + while (sc < len && pr2six[(int)src[srcPos + sc++] & 0xFF] <= 63); + + nprbytes = sc - 1; + return ((nprbytes + 3) / 4) * 3; + } + + public static int decode(byte[] src, int srcPos, byte[] dst, + int dstPos, int len) + throws IndexOutOfBoundsException, NullPointerException + { + int nd; + int sc = 0; + int sp = srcPos; + int dp = dstPos; + int nprbytes; + + while (sc < len && pr2six[(int)src[srcPos + sc++] & 0xFF] <= 63); + + nprbytes = sc - 1; + nd = ((nprbytes + 3) / 4) * 3; + + while (nprbytes > 4) { + dst[dp++] = (byte)(pr2six[src[sp + 0]] << 2 | pr2six[src[sp + 1]] >> 4); + dst[dp++] = (byte)(pr2six[src[sp + 1]] << 4 | pr2six[src[sp + 2]] >> 2); + dst[dp++] = (byte)(pr2six[src[sp + 2]] << 6 | pr2six[src[sp + 3]]); + sp += 4; + nprbytes -= 4; + } + + /* Note: (nprbytes == 1) would be an error, so just ingore that case */ + if (nprbytes > 1) + dst[dp++] = (byte)(pr2six[src[sp + 0]] << 2 | pr2six[src[sp + 1]] >> 4); + if (nprbytes > 2) + dst[dp++] = (byte)(pr2six[src[sp + 1]] << 4 | pr2six[src[sp + 2]] >> 2); + if (nprbytes > 3) + dst[dp++] = (byte)(pr2six[src[sp + 2]] << 6 | pr2six[src[sp + 3]]); + + nd -= (4 - nprbytes) & 3; + return nd; + } + + public static String decode(String string) + { + try { + byte [] data = string.getBytes("8859_1"); + byte [] dest = new byte[decodeLength(data, 0, data.length)]; + + int ndecoded = decode(data, 0, dest, 0, data.length); + return new String(dest, 0, ndecoded); + } catch (UnsupportedEncodingException e) { + return ""; + } + } + +} + Propchange: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/util/Base64.java ------------------------------------------------------------------------------ svn:eol-style = native