001: /*
002: * Modified by Nabh Information Systems, Inc.
003: * Modifications (c) 2006 Nabh Information Systems, Inc.
004: *
005: * Copyright 2001-2004 The Apache Software Foundation.
006: *
007: * Licensed under the Apache License, Version 2.0 (the "License");
008: * you may not use this file except in compliance with the License.
009: * You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019: package com.nabhinc.util;
020:
021: import java.io.IOException;
022: import java.io.OutputStream;
023: import java.io.Writer;
024:
025: /**
026: *
027: * @author TAMURA Kent <kent@trl.ibm.co.jp>
028: */
029: public class Base64 {
030: private static final char[] S_BASE64CHAR = { 'A', 'B', 'C', 'D',
031: 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
032: 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
033: 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
034: 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
035: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
036: private static final char S_BASE64PAD = '=';
037: private static final byte[] S_DECODETABLE = new byte[128];
038: static {
039: for (int i = 0; i < S_DECODETABLE.length; i++)
040: S_DECODETABLE[i] = Byte.MAX_VALUE; // 127
041: for (int i = 0; i < S_BASE64CHAR.length; i++)
042: // 0 to 63
043: S_DECODETABLE[S_BASE64CHAR[i]] = (byte) i;
044: }
045:
046: private static int decode0(char[] ibuf, byte[] obuf, int wp) {
047: int outlen = 3;
048: if (ibuf[3] == S_BASE64PAD)
049: outlen = 2;
050: if (ibuf[2] == S_BASE64PAD)
051: outlen = 1;
052: int b0 = S_DECODETABLE[ibuf[0]];
053: int b1 = S_DECODETABLE[ibuf[1]];
054: int b2 = S_DECODETABLE[ibuf[2]];
055: int b3 = S_DECODETABLE[ibuf[3]];
056: switch (outlen) {
057: case 1:
058: obuf[wp] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
059: return 1;
060: case 2:
061: obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
062: obuf[wp] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
063: return 2;
064: case 3:
065: obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
066: obuf[wp++] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
067: obuf[wp] = (byte) (b2 << 6 & 0xc0 | b3 & 0x3f);
068: return 3;
069: default:
070: throw new RuntimeException("Internal error.");
071: }
072: }
073:
074: /**
075: *
076: */
077: public static byte[] decode(char[] data, int off, int len) {
078: char[] ibuf = new char[4];
079: int ibufcount = 0;
080: byte[] obuf = new byte[len / 4 * 3 + 3];
081: int obufcount = 0;
082: for (int i = off; i < off + len; i++) {
083: char ch = data[i];
084: if (ch == S_BASE64PAD || ch < S_DECODETABLE.length
085: && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
086: ibuf[ibufcount++] = ch;
087: if (ibufcount == ibuf.length) {
088: ibufcount = 0;
089: obufcount += decode0(ibuf, obuf, obufcount);
090: }
091: }
092: }
093: if (obufcount == obuf.length)
094: return obuf;
095: byte[] ret = new byte[obufcount];
096: System.arraycopy(obuf, 0, ret, 0, obufcount);
097: return ret;
098: }
099:
100: /**
101: *
102: */
103: public static byte[] decode(String data) {
104: char[] ibuf = new char[4];
105: int ibufcount = 0;
106: byte[] obuf = new byte[data.length() / 4 * 3 + 3];
107: int obufcount = 0;
108: for (int i = 0; i < data.length(); i++) {
109: char ch = data.charAt(i);
110: if (ch == S_BASE64PAD || ch < S_DECODETABLE.length
111: && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
112: ibuf[ibufcount++] = ch;
113: if (ibufcount == ibuf.length) {
114: ibufcount = 0;
115: obufcount += decode0(ibuf, obuf, obufcount);
116: }
117: }
118: }
119: if (obufcount == obuf.length)
120: return obuf;
121: byte[] ret = new byte[obufcount];
122: System.arraycopy(obuf, 0, ret, 0, obufcount);
123: return ret;
124: }
125:
126: /**
127: *
128: */
129: public static void decode(char[] data, int off, int len,
130: OutputStream ostream) throws IOException {
131: char[] ibuf = new char[4];
132: int ibufcount = 0;
133: byte[] obuf = new byte[3];
134: for (int i = off; i < off + len; i++) {
135: char ch = data[i];
136: if (ch == S_BASE64PAD || ch < S_DECODETABLE.length
137: && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
138: ibuf[ibufcount++] = ch;
139: if (ibufcount == ibuf.length) {
140: ibufcount = 0;
141: int obufcount = decode0(ibuf, obuf, 0);
142: ostream.write(obuf, 0, obufcount);
143: }
144: }
145: }
146: }
147:
148: /**
149: *
150: */
151: public static void decode(String data, OutputStream ostream)
152: throws IOException {
153: char[] ibuf = new char[4];
154: int ibufcount = 0;
155: byte[] obuf = new byte[3];
156: for (int i = 0; i < data.length(); i++) {
157: char ch = data.charAt(i);
158: if (ch == S_BASE64PAD || ch < S_DECODETABLE.length
159: && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
160: ibuf[ibufcount++] = ch;
161: if (ibufcount == ibuf.length) {
162: ibufcount = 0;
163: int obufcount = decode0(ibuf, obuf, 0);
164: ostream.write(obuf, 0, obufcount);
165: }
166: }
167: }
168: }
169:
170: /**
171: * Returns base64 representation of specified byte array.
172: */
173: public static String encode(byte[] data) {
174: return encode(data, 0, data.length);
175: }
176:
177: /**
178: * Returns base64 representation of specified byte array.
179: */
180: public static String encode(byte[] data, int off, int len) {
181: if (len <= 0)
182: return "";
183: char[] out = new char[len / 3 * 4 + 4];
184: int rindex = off;
185: int windex = 0;
186: int rest = len - off;
187: while (rest >= 3) {
188: int i = ((data[rindex] & 0xff) << 16)
189: + ((data[rindex + 1] & 0xff) << 8)
190: + (data[rindex + 2] & 0xff);
191: out[windex++] = S_BASE64CHAR[i >> 18];
192: out[windex++] = S_BASE64CHAR[(i >> 12) & 0x3f];
193: out[windex++] = S_BASE64CHAR[(i >> 6) & 0x3f];
194: out[windex++] = S_BASE64CHAR[i & 0x3f];
195: rindex += 3;
196: rest -= 3;
197: }
198: if (rest == 1) {
199: int i = data[rindex] & 0xff;
200: out[windex++] = S_BASE64CHAR[i >> 2];
201: out[windex++] = S_BASE64CHAR[(i << 4) & 0x3f];
202: out[windex++] = S_BASE64PAD;
203: out[windex++] = S_BASE64PAD;
204: } else if (rest == 2) {
205: int i = ((data[rindex] & 0xff) << 8)
206: + (data[rindex + 1] & 0xff);
207: out[windex++] = S_BASE64CHAR[i >> 10];
208: out[windex++] = S_BASE64CHAR[(i >> 4) & 0x3f];
209: out[windex++] = S_BASE64CHAR[(i << 2) & 0x3f];
210: out[windex++] = S_BASE64PAD;
211: }
212: return new String(out, 0, windex);
213: }
214:
215: /**
216: * Outputs base64 representation of the specified byte array to a byte stream.
217: */
218: public static void encode(byte[] data, int off, int len,
219: OutputStream ostream) throws IOException {
220: if (len <= 0)
221: return;
222: byte[] out = new byte[4];
223: int rindex = off;
224: int rest = len - off;
225: while (rest >= 3) {
226: int i = ((data[rindex] & 0xff) << 16)
227: + ((data[rindex + 1] & 0xff) << 8)
228: + (data[rindex + 2] & 0xff);
229: out[0] = (byte) S_BASE64CHAR[i >> 18];
230: out[1] = (byte) S_BASE64CHAR[(i >> 12) & 0x3f];
231: out[2] = (byte) S_BASE64CHAR[(i >> 6) & 0x3f];
232: out[3] = (byte) S_BASE64CHAR[i & 0x3f];
233: ostream.write(out, 0, 4);
234: rindex += 3;
235: rest -= 3;
236: }
237: if (rest == 1) {
238: int i = data[rindex] & 0xff;
239: out[0] = (byte) S_BASE64CHAR[i >> 2];
240: out[1] = (byte) S_BASE64CHAR[(i << 4) & 0x3f];
241: out[2] = (byte) S_BASE64PAD;
242: out[3] = (byte) S_BASE64PAD;
243: ostream.write(out, 0, 4);
244: } else if (rest == 2) {
245: int i = ((data[rindex] & 0xff) << 8)
246: + (data[rindex + 1] & 0xff);
247: out[0] = (byte) S_BASE64CHAR[i >> 10];
248: out[1] = (byte) S_BASE64CHAR[(i >> 4) & 0x3f];
249: out[2] = (byte) S_BASE64CHAR[(i << 2) & 0x3f];
250: out[3] = (byte) S_BASE64PAD;
251: ostream.write(out, 0, 4);
252: }
253: }
254:
255: /**
256: * Outputs base64 representation of the specified byte array to a character stream.
257: */
258: public static void encode(byte[] data, int off, int len,
259: Writer writer) throws IOException {
260: if (len <= 0)
261: return;
262: char[] out = new char[4];
263: int rindex = off;
264: int rest = len - off;
265: int output = 0;
266: while (rest >= 3) {
267: int i = ((data[rindex] & 0xff) << 16)
268: + ((data[rindex + 1] & 0xff) << 8)
269: + (data[rindex + 2] & 0xff);
270: out[0] = S_BASE64CHAR[i >> 18];
271: out[1] = S_BASE64CHAR[(i >> 12) & 0x3f];
272: out[2] = S_BASE64CHAR[(i >> 6) & 0x3f];
273: out[3] = S_BASE64CHAR[i & 0x3f];
274: writer.write(out, 0, 4);
275: rindex += 3;
276: rest -= 3;
277: output += 4;
278: if (output % 76 == 0)
279: writer.write("\n");
280: }
281: if (rest == 1) {
282: int i = data[rindex] & 0xff;
283: out[0] = S_BASE64CHAR[i >> 2];
284: out[1] = S_BASE64CHAR[(i << 4) & 0x3f];
285: out[2] = S_BASE64PAD;
286: out[3] = S_BASE64PAD;
287: writer.write(out, 0, 4);
288: } else if (rest == 2) {
289: int i = ((data[rindex] & 0xff) << 8)
290: + (data[rindex + 1] & 0xff);
291: out[0] = S_BASE64CHAR[i >> 10];
292: out[1] = S_BASE64CHAR[(i >> 4) & 0x3f];
293: out[2] = S_BASE64CHAR[(i << 2) & 0x3f];
294: out[3] = S_BASE64PAD;
295: writer.write(out, 0, 4);
296: }
297: }
298: }
|