001: package com.protomatter.util;
002:
003: /**
004: * {{{ The Protomatter Software License, Version 1.0
005: * derived from The Apache Software License, Version 1.1
006: *
007: * Copyright (c) 1998-2002 Nate Sammons. All rights reserved.
008: *
009: * Redistribution and use in source and binary forms, with or without
010: * modification, are permitted provided that the following conditions
011: * are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution,
022: * if any, must include the following acknowledgment:
023: * "This product includes software developed for the
024: * Protomatter Software Project
025: * (http://protomatter.sourceforge.net/)."
026: * Alternately, this acknowledgment may appear in the software itself,
027: * if and wherever such third-party acknowledgments normally appear.
028: *
029: * 4. The names "Protomatter" and "Protomatter Software Project" must
030: * not be used to endorse or promote products derived from this
031: * software without prior written permission. For written
032: * permission, please contact support@protomatter.com.
033: *
034: * 5. Products derived from this software may not be called "Protomatter",
035: * nor may "Protomatter" appear in their name, without prior written
036: * permission of the Protomatter Software Project
037: * (support@protomatter.com).
038: *
039: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
040: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
041: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
042: * DISCLAIMED. IN NO EVENT SHALL THE PROTOMATTER SOFTWARE PROJECT OR
043: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
044: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
045: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
046: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
047: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
048: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
049: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
050: * SUCH DAMAGE. }}}
051: */
052:
053: /**
054: * Base64 encoder/decoder. Does not stream, so be careful with
055: * using large amounts of data.
056: */
057: public class Base64 {
058: private Base64() {
059: super ();
060: }
061:
062: /**
063: * Encode some data and return a String.
064: */
065: public final static String encode(byte[] d) {
066: if (d == null)
067: return null;
068: byte data[] = new byte[d.length + 2];
069: System.arraycopy(d, 0, data, 0, d.length);
070: byte dest[] = new byte[(data.length / 3) * 4];
071:
072: // 3-byte to 4-byte conversion
073: for (int sidx = 0, didx = 0; sidx < d.length; sidx += 3, didx += 4) {
074: dest[didx] = (byte) ((data[sidx] >>> 2) & 077);
075: dest[didx + 1] = (byte) ((data[sidx + 1] >>> 4) & 017 | (data[sidx] << 4) & 077);
076: dest[didx + 2] = (byte) ((data[sidx + 2] >>> 6) & 003 | (data[sidx + 1] << 2) & 077);
077: dest[didx + 3] = (byte) (data[sidx + 2] & 077);
078: }
079:
080: // 0-63 to ascii printable conversion
081: for (int idx = 0; idx < dest.length; idx++) {
082: if (dest[idx] < 26)
083: dest[idx] = (byte) (dest[idx] + 'A');
084: else if (dest[idx] < 52)
085: dest[idx] = (byte) (dest[idx] + 'a' - 26);
086: else if (dest[idx] < 62)
087: dest[idx] = (byte) (dest[idx] + '0' - 52);
088: else if (dest[idx] < 63)
089: dest[idx] = (byte) '+';
090: else
091: dest[idx] = (byte) '/';
092: }
093:
094: // add padding
095: for (int idx = dest.length - 1; idx > (d.length * 4) / 3; idx--) {
096: dest[idx] = (byte) '=';
097: }
098: return new String(dest);
099: }
100:
101: /**
102: * Decode data and return bytes.
103: */
104: public final static byte[] decode(String str) {
105: if (str == null)
106: return null;
107: return decode(str.getBytes());
108: }
109:
110: /**
111: * Decode data and return bytes. Assumes that the data passed
112: * in is ASCII text.
113: */
114: public final static byte[] decode(byte[] data) {
115: int tail = data.length;
116: while (data[tail - 1] == '=')
117: tail--;
118: byte dest[] = new byte[tail - data.length / 4];
119:
120: // ascii printable to 0-63 conversion
121: for (int idx = 0; idx < data.length; idx++) {
122: if (data[idx] == '=')
123: data[idx] = 0;
124: else if (data[idx] == '/')
125: data[idx] = 63;
126: else if (data[idx] == '+')
127: data[idx] = 62;
128: else if (data[idx] >= '0' && data[idx] <= '9')
129: data[idx] = (byte) (data[idx] - ('0' - 52));
130: else if (data[idx] >= 'a' && data[idx] <= 'z')
131: data[idx] = (byte) (data[idx] - ('a' - 26));
132: else if (data[idx] >= 'A' && data[idx] <= 'Z')
133: data[idx] = (byte) (data[idx] - 'A');
134: }
135:
136: // 4-byte to 3-byte conversion
137: int sidx, didx;
138: for (sidx = 0, didx = 0; didx < dest.length - 2; sidx += 4, didx += 3) {
139: dest[didx] = (byte) (((data[sidx] << 2) & 255) | ((data[sidx + 1] >>> 4) & 3));
140: dest[didx + 1] = (byte) (((data[sidx + 1] << 4) & 255) | ((data[sidx + 2] >>> 2) & 017));
141: dest[didx + 2] = (byte) (((data[sidx + 2] << 6) & 255) | (data[sidx + 3] & 077));
142: }
143: if (didx < dest.length) {
144: dest[didx] = (byte) (((data[sidx] << 2) & 255) | ((data[sidx + 1] >>> 4) & 3));
145: }
146: if (++didx < dest.length) {
147: dest[didx] = (byte) (((data[sidx + 1] << 4) & 255) | ((data[sidx + 2] >>> 2) & 017));
148: }
149: return dest;
150: }
151:
152: /**
153: * A simple test that encodes and decodes the first commandline argument.
154: */
155: public static final void main(String args[]) {
156: if (args.length != 1) {
157: System.out.println("Usage: Base64 string");
158: System.exit(0);
159: }
160: try {
161: String e = Base64.encode(args[0].getBytes());
162: String d = new String(Base64.decode(e));
163: System.out.println("Input = '" + args[0] + "'");
164: System.out.println("Encoded = '" + e + "'");
165: System.out.println("Decoded = '" + d + "'");
166: } catch (Exception x) {
167: x.printStackTrace();
168: }
169: }
170: }
|