001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Xerces" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 1999, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057:
058: package org.continuent.sequoia.common.stream.encoding;
059:
060: /**
061: * This class provides encode/decode for RFC 2045 Base64 as defined by RFC 2045,
062: * N. Freed and N. Borenstein. RFC 2045: Multipurpose Internet Mail Extensions
063: * (MIME) Part One: Format of Internet Message Bodies. Reference 1996 Available
064: * at: http://www.ietf.org/rfc/rfc2045.txt This class is used by XML Schema
065: * binary format validation This implementation does not encode/decode streaming
066: * data. You need the data that you will encode/decode already on a byte arrray.
067: *
068: * @author Jeffrey Rodriguez
069: * @author Sandy Gao
070: * @version $Id: Base64.java,v 1.1 2005/08/01 14:28:05 emmanuel Exp $
071: */
072: public final class Base64 {
073: private static final int BASELENGTH = 255;
074: private static final int LOOKUPLENGTH = 64;
075: private static final int TWENTYFOURBITGROUP = 24;
076: private static final int EIGHTBIT = 8;
077: private static final int SIXTEENBIT = 16;
078: private static final int FOURBYTE = 4;
079: private static final int SIGN = -128;
080: private static final char PAD = '=';
081: private static final boolean F_DEBUG = false;
082: private static final byte[] BASE64_ALPHABET = new byte[BASELENGTH];
083: private static final char[] LOOKUP_BASE64_ALPHABET = new char[LOOKUPLENGTH];
084:
085: static {
086:
087: for (int i = 0; i < BASELENGTH; i++) {
088: BASE64_ALPHABET[i] = -1;
089: }
090: for (int i = 'Z'; i >= 'A'; i--) {
091: BASE64_ALPHABET[i] = (byte) (i - 'A');
092: }
093: for (int i = 'z'; i >= 'a'; i--) {
094: BASE64_ALPHABET[i] = (byte) (i - 'a' + 26);
095: }
096:
097: for (int i = '9'; i >= '0'; i--) {
098: BASE64_ALPHABET[i] = (byte) (i - '0' + 52);
099: }
100:
101: BASE64_ALPHABET['+'] = 62;
102: BASE64_ALPHABET['/'] = 63;
103:
104: for (int i = 0; i <= 25; i++)
105: LOOKUP_BASE64_ALPHABET[i] = (char) ('A' + i);
106:
107: for (int i = 26, j = 0; i <= 51; i++, j++)
108: LOOKUP_BASE64_ALPHABET[i] = (char) ('a' + j);
109:
110: for (int i = 52, j = 0; i <= 61; i++, j++)
111: LOOKUP_BASE64_ALPHABET[i] = (char) ('0' + j);
112: LOOKUP_BASE64_ALPHABET[62] = '+';
113: LOOKUP_BASE64_ALPHABET[63] = '/';
114: }
115:
116: protected static boolean isWhiteSpace(char octect) {
117: return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
118: }
119:
120: protected static boolean isPad(char octect) {
121: return (octect == PAD);
122: }
123:
124: protected static boolean isData(char octect) {
125: return (BASE64_ALPHABET[octect] != -1);
126: }
127:
128: protected static boolean isBase64(char octect) {
129: return (isWhiteSpace(octect) || isPad(octect) || isData(octect));
130: }
131:
132: /**
133: * Encodes hex octects into Base64
134: *
135: * @param binaryData Array containing binaryData
136: * @return Encoded Base64 array
137: */
138: public static String encode(byte[] binaryData) {
139:
140: if (binaryData == null)
141: return null;
142:
143: int lengthDataBits = binaryData.length * EIGHTBIT;
144: if (lengthDataBits == 0) {
145: return "";
146: }
147:
148: int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
149: int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
150: int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1
151: : numberTriplets;
152: int numberLines = (numberQuartet - 1) / 19 + 1;
153: char[] encodedData = null;
154:
155: encodedData = new char[numberQuartet * 4 + numberLines];
156:
157: byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
158:
159: int encodedIndex = 0;
160: int dataIndex = 0;
161: int i = 0;
162: if (F_DEBUG) {
163: System.out
164: .println("number of triplets = " + numberTriplets);
165: }
166:
167: for (int line = 0; line < numberLines - 1; line++) {
168: for (int quartet = 0; quartet < 19; quartet++) {
169: b1 = binaryData[dataIndex++];
170: b2 = binaryData[dataIndex++];
171: b3 = binaryData[dataIndex++];
172:
173: if (F_DEBUG) {
174: System.out.println("b1= " + b1 + ", b2= " + b2
175: + ", b3= " + b3);
176: }
177:
178: l = (byte) (b2 & 0x0f);
179: k = (byte) (b1 & 0x03);
180:
181: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
182: : (byte) ((b1) >> 2 ^ 0xc0);
183:
184: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
185: : (byte) ((b2) >> 4 ^ 0xf0);
186: byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
187: : (byte) ((b3) >> 6 ^ 0xfc);
188:
189: if (F_DEBUG) {
190: System.out.println("val2 = " + val2);
191: System.out.println("k4 = " + (k << 4));
192: System.out.println("vak = " + (val2 | (k << 4)));
193: }
194:
195: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val1];
196: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val2
197: | (k << 4)];
198: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[(l << 2)
199: | val3];
200: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[b3 & 0x3f];
201:
202: i++;
203: }
204: encodedData[encodedIndex++] = 0xa;
205: }
206:
207: for (; i < numberTriplets; i++) {
208: b1 = binaryData[dataIndex++];
209: b2 = binaryData[dataIndex++];
210: b3 = binaryData[dataIndex++];
211:
212: if (F_DEBUG) {
213: System.out.println("b1= " + b1 + ", b2= " + b2
214: + ", b3= " + b3);
215: }
216:
217: l = (byte) (b2 & 0x0f);
218: k = (byte) (b1 & 0x03);
219:
220: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
221: : (byte) ((b1) >> 2 ^ 0xc0);
222:
223: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
224: : (byte) ((b2) >> 4 ^ 0xf0);
225: byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
226: : (byte) ((b3) >> 6 ^ 0xfc);
227:
228: if (F_DEBUG) {
229: System.out.println("val2 = " + val2);
230: System.out.println("k4 = " + (k << 4));
231: System.out.println("vak = " + (val2 | (k << 4)));
232: }
233:
234: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val1];
235: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val2
236: | (k << 4)];
237: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[(l << 2)
238: | val3];
239: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[b3 & 0x3f];
240: }
241:
242: // form integral number of 6-bit groups
243: if (fewerThan24bits == EIGHTBIT) {
244: b1 = binaryData[dataIndex];
245: k = (byte) (b1 & 0x03);
246: if (F_DEBUG) {
247: System.out.println("b1=" + b1);
248: System.out.println("b1<<2 = " + (b1 >> 2));
249: }
250: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
251: : (byte) ((b1) >> 2 ^ 0xc0);
252: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val1];
253: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[k << 4];
254: encodedData[encodedIndex++] = PAD;
255: encodedData[encodedIndex++] = PAD;
256: } else if (fewerThan24bits == SIXTEENBIT) {
257: b1 = binaryData[dataIndex];
258: b2 = binaryData[dataIndex + 1];
259: l = (byte) (b2 & 0x0f);
260: k = (byte) (b1 & 0x03);
261:
262: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
263: : (byte) ((b1) >> 2 ^ 0xc0);
264: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
265: : (byte) ((b2) >> 4 ^ 0xf0);
266:
267: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val1];
268: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val2
269: | (k << 4)];
270: encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[l << 2];
271: encodedData[encodedIndex++] = PAD;
272: }
273:
274: encodedData[encodedIndex] = 0xa;
275:
276: return new String(encodedData);
277: }
278:
279: /**
280: * Decodes Base64 data into octects
281: *
282: * @param encoded String encoded in Base64
283: * @return Byte array containing decoded data.
284: */
285: public static byte[] decode(String encoded) {
286:
287: if (encoded == null)
288: return null;
289:
290: char[] base64Data = encoded.toCharArray();
291: // remove white spaces
292: int len = removeWhiteSpace(base64Data);
293:
294: if (len % FOURBYTE != 0) {
295: return null;//should be divisible by four
296: }
297:
298: int numberQuadruple = (len / FOURBYTE);
299:
300: if (numberQuadruple == 0)
301: return new byte[0];
302:
303: byte[] decodedData = null;
304: byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
305: char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
306:
307: int i = 0;
308: int encodedIndex = 0;
309: int dataIndex = 0;
310: decodedData = new byte[(numberQuadruple) * 3];
311:
312: for (; i < numberQuadruple - 1; i++) {
313: d1 = base64Data[dataIndex++];
314: d2 = base64Data[dataIndex++];
315: d3 = base64Data[dataIndex++];
316: d4 = base64Data[dataIndex++];
317: if (!isData(d1) || !isData(d2) || !isData(d3)
318: || !isData(d4))
319: return null;//if found "no data" just return null
320:
321: b1 = BASE64_ALPHABET[d1];
322: b2 = BASE64_ALPHABET[d2];
323: b3 = BASE64_ALPHABET[d3];
324: b4 = BASE64_ALPHABET[d4];
325:
326: decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
327: decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
328: decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
329: }
330:
331: d1 = base64Data[dataIndex++];
332: d2 = base64Data[dataIndex++];
333: if (!isData(d1) || !isData(d2)) {
334: return null;//if found "no data" just return null
335: }
336:
337: b1 = BASE64_ALPHABET[d1];
338: b2 = BASE64_ALPHABET[d2];
339:
340: d3 = base64Data[dataIndex++];
341: d4 = base64Data[dataIndex++];
342: if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters
343: if (isPad(d3) && isPad(d4)) { //Two PAD e.g. 3c[Pad][Pad]
344: if ((b2 & 0xf) != 0)//last 4 bits should be zero
345: return null;
346: byte[] tmp = new byte[i * 3 + 1];
347: System.arraycopy(decodedData, 0, tmp, 0, i * 3);
348: tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
349: return tmp;
350: } else if (!isPad(d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
351: b3 = BASE64_ALPHABET[d3];
352: if ((b3 & 0x3) != 0)//last 2 bits should be zero
353: return null;
354: byte[] tmp = new byte[i * 3 + 2];
355: System.arraycopy(decodedData, 0, tmp, 0, i * 3);
356: tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
357: tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
358: return tmp;
359: } else {
360: return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X
361: // is non data
362: }
363: } else { //No PAD e.g 3cQl
364: b3 = BASE64_ALPHABET[d3];
365: b4 = BASE64_ALPHABET[d4];
366: decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
367: decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
368: decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
369:
370: }
371:
372: return decodedData;
373: }
374:
375: /**
376: * remove WhiteSpace from MIME containing encoded Base64 data.
377: *
378: * @param data the byte array of base64 data (with WS)
379: * @return the new length
380: */
381: protected static int removeWhiteSpace(char[] data) {
382: if (data == null)
383: return 0;
384:
385: // count characters that's not whitespace
386: int newSize = 0;
387: int len = data.length;
388: for (int i = 0; i < len; i++) {
389: if (!isWhiteSpace(data[i]))
390: data[newSize++] = data[i];
391: }
392: return newSize;
393: }
394: }
|