001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.util.transformers;
011:
012: import java.util.HashMap;
013: import java.util.Map;
014:
015: // still present in java 1.6, but give horrible warnings during compilation
016: //import sun.misc.BASE64Decoder;
017: //import sun.misc.BASE64Encoder;
018:
019: /**
020: * Code taken from {@link http://www.source-code.biz/snippets/java/2.htm}
021: *
022: * @author Michiel Meeuwissen
023: */
024:
025: public class Base64 extends ByteArrayToCharTransformer implements
026: ByteToCharTransformer, ConfigurableTransformer {
027: private final static String ENCODING = "BASE64";
028: private final static int BASE_64 = 1;
029:
030: // Mapping table from 6-bit nibbles to Base64 characters.
031: private static char[] map1 = new char[64];
032: static {
033: int i = 0;
034: for (char c = 'A'; c <= 'Z'; c++)
035: map1[i++] = c;
036: for (char c = 'a'; c <= 'z'; c++)
037: map1[i++] = c;
038: for (char c = '0'; c <= '9'; c++)
039: map1[i++] = c;
040: map1[i++] = '+';
041: map1[i++] = '/';
042: }
043:
044: // Mapping table from Base64 characters to 6-bit nibbles.
045: private static byte[] map2 = new byte[128];
046: static {
047: for (int i = 0; i < map2.length; i++)
048: map2[i] = -1;
049: for (int i = 0; i < 64; i++)
050: map2[map1[i]] = (byte) i;
051: }
052:
053: int to = BASE_64;
054:
055: public void configure(int t) {
056: to = t;
057: }
058:
059: /**
060: * Used when registering this class as a possible Transformer
061: */
062:
063: public Map<String, Config> transformers() {
064: Map<String, Config> h = new HashMap<String, Config>();
065: h.put(ENCODING, new Config(Base64.class, BASE_64,
066: "Base 64 encoding base on sun.misc.BASE64* classes"));
067: return h;
068: }
069:
070: public String transform(byte[] in) {
071: int iLen = in.length;
072: int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
073: int oLen = ((iLen + 2) / 3) * 4; // output length including padding
074: char[] out = new char[oLen];
075: int ip = 0;
076: int op = 0;
077: while (ip < iLen) {
078: int i0 = in[ip++] & 0xff;
079: int i1 = ip < iLen ? in[ip++] & 0xff : 0;
080: int i2 = ip < iLen ? in[ip++] & 0xff : 0;
081: int o0 = i0 >>> 2;
082: int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
083: int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
084: int o3 = i2 & 0x3F;
085: out[op++] = map1[o0];
086: out[op++] = map1[o1];
087: out[op] = op < oDataLen ? map1[o2] : '=';
088: op++;
089: out[op] = op < oDataLen ? map1[o3] : '=';
090: op++;
091: }
092: return new String(out);
093: }
094:
095: public byte[] transformBack(String r) {
096: char[] in = r.toCharArray();
097: int iLen = in.length;
098: if (iLen % 4 != 0)
099: throw new IllegalArgumentException(
100: "Length of Base64 encoded input string is not a multiple of 4.");
101: while (iLen > 0 && in[iLen - 1] == '=')
102: iLen--;
103: int oLen = (iLen * 3) / 4;
104: byte[] out = new byte[oLen];
105: int ip = 0;
106: int op = 0;
107: while (ip < iLen) {
108: int i0 = in[ip++];
109: int i1 = in[ip++];
110: int i2 = ip < iLen ? in[ip++] : 'A';
111: int i3 = ip < iLen ? in[ip++] : 'A';
112: if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
113: throw new IllegalArgumentException(
114: "Illegal character in Base64 encoded data.");
115: int b0 = map2[i0];
116: int b1 = map2[i1];
117: int b2 = map2[i2];
118: int b3 = map2[i3];
119: if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
120: throw new IllegalArgumentException(
121: "Illegal character in Base64 encoded data.");
122: int o0 = (b0 << 2) | (b1 >>> 4);
123: int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
124: int o2 = ((b2 & 3) << 6) | b3;
125: out[op++] = (byte) o0;
126: if (op < oLen)
127: out[op++] = (byte) o1;
128: if (op < oLen)
129: out[op++] = (byte) o2;
130: }
131: return out;
132: }
133:
134: public String getEncoding() {
135: return ENCODING;
136: }
137: }
|