001: package com.meterware.httpunit;
002:
003: /********************************************************************************************************************
004: * $Id: Base64.java,v 1.4 2002/12/24 15:17:17 russgold Exp $
005: *
006: * Copyright (c) 2000-2002 by Russell Gold
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
009: * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
010: * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
011: * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included in all copies or substantial portions
014: * of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
017: * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
018: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
019: * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
020: * DEALINGS IN THE SOFTWARE.
021: *
022: *******************************************************************************************************************/
023:
024: /**
025: * A utility class to convert to and from base 64 encoding.
026: *
027: * @author <a href="mailto:russgold@httpunit.org">Russell Gold</a>
028: **/
029: public class Base64 {
030:
031: final static String encodingChar = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
032:
033: /**
034: * Returns the base 64 encoded equivalent of a supplied string.
035: * @param source the string to encode
036: */
037: public static String encode(String source) {
038: char[] sourceBytes = getPaddedBytes(source);
039: int numGroups = (sourceBytes.length + 2) / 3;
040: char[] targetBytes = new char[4];
041: char[] target = new char[4 * numGroups];
042:
043: for (int group = 0; group < numGroups; group++) {
044: convert3To4(sourceBytes, group * 3, targetBytes);
045: for (int i = 0; i < targetBytes.length; i++) {
046: target[i + 4 * group] = encodingChar
047: .charAt(targetBytes[i]);
048: }
049: }
050:
051: int numPadBytes = sourceBytes.length - source.length();
052:
053: for (int i = target.length - numPadBytes; i < target.length; i++)
054: target[i] = '=';
055: return new String(target);
056: }
057:
058: private static char[] getPaddedBytes(String source) {
059: char[] converted = source.toCharArray();
060: int requiredLength = 3 * ((converted.length + 2) / 3);
061: char[] result = new char[requiredLength];
062: System.arraycopy(converted, 0, result, 0, converted.length);
063: return result;
064: }
065:
066: private static void convert3To4(char[] source, int sourceIndex,
067: char[] target) {
068: target[0] = (char) (source[sourceIndex] >>> 2);
069: target[1] = (char) (((source[sourceIndex] & 0x03) << 4) | (source[sourceIndex + 1] >>> 4));
070: target[2] = (char) (((source[sourceIndex + 1] & 0x0f) << 2) | (source[sourceIndex + 2] >>> 6));
071: target[3] = (char) (source[sourceIndex + 2] & 0x3f);
072: }
073:
074: /**
075: * Returns the plaintext equivalent of a base 64-encoded string.
076: * @param source a base 64 string (which must have a multiple of 4 characters)
077: */
078: public static String decode(String source) {
079: if (source.length() % 4 != 0)
080: throw new RuntimeException(
081: "valid Base64 codes have a multiple of 4 characters");
082: int numGroups = source.length() / 4;
083: int numExtraBytes = source.endsWith("==") ? 2 : (source
084: .endsWith("=") ? 1 : 0);
085: byte[] targetBytes = new byte[3 * numGroups];
086: byte[] sourceBytes = new byte[4];
087: for (int group = 0; group < numGroups; group++) {
088: for (int i = 0; i < sourceBytes.length; i++) {
089: sourceBytes[i] = (byte) Math.max(0, encodingChar
090: .indexOf(source.charAt(4 * group + i)));
091: }
092: convert4To3(sourceBytes, targetBytes, group * 3);
093: }
094: return new String(targetBytes, 0, targetBytes.length
095: - numExtraBytes);
096: }
097:
098: private static void convert4To3(byte[] source, byte[] target,
099: int targetIndex) {
100: target[targetIndex] = (byte) ((source[0] << 2) | (source[1] >>> 4));
101: target[targetIndex + 1] = (byte) (((source[1] & 0x0f) << 4) | (source[2] >>> 2));
102: target[targetIndex + 2] = (byte) (((source[2] & 0x03) << 6) | (source[3]));
103: }
104:
105: }
|