001: package net.matuschek.util;
002:
003: /***************************************************************
004:
005: Copyright (c) 1998, 1999 Nate Sammons <nate@protomatter.com>
006: This library is free software; you can redistribute it and/or
007: modify it under the terms of the GNU Library General Public
008: License as published by the Free Software Foundation; either
009: version 2 of the License, or (at your option) any later version.
010:
011: This library is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: Library General Public License for more details.
015:
016: You should have received a copy of the GNU Library General Public
017: License along with this library; if not, write to the
018: Free Software Foundation, Inc., 59 Temple Place - Suite 330,
019: Boston, MA 02111-1307, USA.
020:
021: Contact support@protomatter.com with your questions, comments,
022: gripes, praise, etc...
023:
024: ***************************************************************/
025:
026: /***************************************************************
027: - moved to the net.matuschek.util tree by Daniel Matuschek
028: - replaced deprecated getBytes() method in method decode
029: - added String encode(String) method to encode a String to
030: base64
031: ***************************************************************/
032:
033: /**
034: * Base64 encoder/decoder. Does not stream, so be careful with
035: * using large amounts of data
036: *
037: * @author Nate Sammons
038: * @author Daniel Matuschek
039: * @version $Id: Base64.java,v 1.4 2001/04/17 10:09:27 matuschd Exp $
040: */
041: public class Base64 {
042:
043: private Base64() {
044: super ();
045: }
046:
047: /**
048: * Encode some data and return a String.
049: */
050: public final static String encode(byte[] d) {
051: if (d == null)
052: return null;
053: byte data[] = new byte[d.length + 2];
054: System.arraycopy(d, 0, data, 0, d.length);
055: byte dest[] = new byte[(data.length / 3) * 4];
056:
057: // 3-byte to 4-byte conversion
058: for (int sidx = 0, didx = 0; sidx < d.length; sidx += 3, didx += 4) {
059: dest[didx] = (byte) ((data[sidx] >>> 2) & 077);
060: dest[didx + 1] = (byte) ((data[sidx + 1] >>> 4) & 017 | (data[sidx] << 4) & 077);
061: dest[didx + 2] = (byte) ((data[sidx + 2] >>> 6) & 003 | (data[sidx + 1] << 2) & 077);
062: dest[didx + 3] = (byte) (data[sidx + 2] & 077);
063: }
064:
065: // 0-63 to ascii printable conversion
066: for (int idx = 0; idx < dest.length; idx++) {
067: if (dest[idx] < 26)
068: dest[idx] = (byte) (dest[idx] + 'A');
069: else if (dest[idx] < 52)
070: dest[idx] = (byte) (dest[idx] + 'a' - 26);
071: else if (dest[idx] < 62)
072: dest[idx] = (byte) (dest[idx] + '0' - 52);
073: else if (dest[idx] < 63)
074: dest[idx] = (byte) '+';
075: else
076: dest[idx] = (byte) '/';
077: }
078:
079: // add padding
080: for (int idx = dest.length - 1; idx > (d.length * 4) / 3; idx--) {
081: dest[idx] = (byte) '=';
082: }
083: return new String(dest);
084: }
085:
086: /**
087: * Encode a String using Base64 using the default platform encoding
088: **/
089: public final static String encode(String s) {
090: return encode(s.getBytes());
091: }
092:
093: /**
094: * Decode data and return bytes.
095: */
096: public final static byte[] decode(String str) {
097: if (str == null)
098: return null;
099: byte data[] = str.getBytes();
100: return decode(data);
101: }
102:
103: /**
104: * Decode data and return bytes. Assumes that the data passed
105: * in is ASCII text.
106: */
107: public final static byte[] decode(byte[] data) {
108: int tail = data.length;
109: while (data[tail - 1] == '=')
110: tail--;
111: byte dest[] = new byte[tail - data.length / 4];
112:
113: // ascii printable to 0-63 conversion
114: for (int idx = 0; idx < data.length; idx++) {
115: if (data[idx] == '=')
116: data[idx] = 0;
117: else if (data[idx] == '/')
118: data[idx] = 63;
119: else if (data[idx] == '+')
120: data[idx] = 62;
121: else if (data[idx] >= '0' && data[idx] <= '9')
122: data[idx] = (byte) (data[idx] - ('0' - 52));
123: else if (data[idx] >= 'a' && data[idx] <= 'z')
124: data[idx] = (byte) (data[idx] - ('a' - 26));
125: else if (data[idx] >= 'A' && data[idx] <= 'Z')
126: data[idx] = (byte) (data[idx] - 'A');
127: }
128:
129: // 4-byte to 3-byte conversion
130: int sidx, didx;
131: for (sidx = 0, didx = 0; didx < dest.length - 2; sidx += 4, didx += 3) {
132: dest[didx] = (byte) (((data[sidx] << 2) & 255) | ((data[sidx + 1] >>> 4) & 3));
133: dest[didx + 1] = (byte) (((data[sidx + 1] << 4) & 255) | ((data[sidx + 2] >>> 2) & 017));
134: dest[didx + 2] = (byte) (((data[sidx + 2] << 6) & 255) | (data[sidx + 3] & 077));
135: }
136: if (didx < dest.length) {
137: dest[didx] = (byte) (((data[sidx] << 2) & 255) | ((data[sidx + 1] >>> 4) & 3));
138: }
139: if (++didx < dest.length) {
140: dest[didx] = (byte) (((data[sidx + 1] << 4) & 255) | ((data[sidx + 2] >>> 2) & 017));
141: }
142: return dest;
143: }
144:
145: /**
146: * A simple test that encodes and decodes the first commandline argument.
147: */
148: public static final void main(String[] args) {
149: if (args.length != 1) {
150: System.out.println("Usage: Base64 string");
151: System.exit(0);
152: }
153: try {
154: String e = Base64.encode(args[0].getBytes());
155: String d = new String(Base64.decode(e));
156: System.out.println("Input = '" + args[0] + "'");
157: System.out.println("Encoded = '" + e + "'");
158: System.out.println("Decoded = '" + d + "'");
159: } catch (Exception x) {
160: x.printStackTrace();
161: }
162: }
163: }
|