001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.tomcat.util.buf;
018:
019: /**
020: * This class provides encode/decode for RFC 2045 Base64 as
021: * defined by RFC 2045, N. Freed and N. Borenstein.
022: * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
023: * Part One: Format of Internet Message Bodies. Reference
024: * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
025: * This class is used by XML Schema binary format validation
026: *
027: * @author Jeffrey Rodriguez
028: * @version $Revision: 1.3 $ $Date: 2004/02/24 08:50:06 $
029: */
030:
031: public final class Base64 {
032:
033: static private final int BASELENGTH = 255;
034: static private final int LOOKUPLENGTH = 63;
035: static private final int TWENTYFOURBITGROUP = 24;
036: static private final int EIGHTBIT = 8;
037: static private final int SIXTEENBIT = 16;
038: static private final int SIXBIT = 6;
039: static private final int FOURBYTE = 4;
040:
041: static private final byte PAD = (byte) '=';
042: static private byte[] base64Alphabet = new byte[BASELENGTH];
043: static private byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
044:
045: static {
046:
047: for (int i = 0; i < BASELENGTH; i++) {
048: base64Alphabet[i] = -1;
049: }
050: for (int i = 'Z'; i >= 'A'; i--) {
051: base64Alphabet[i] = (byte) (i - 'A');
052: }
053: for (int i = 'z'; i >= 'a'; i--) {
054: base64Alphabet[i] = (byte) (i - 'a' + 26);
055: }
056:
057: for (int i = '9'; i >= '0'; i--) {
058: base64Alphabet[i] = (byte) (i - '0' + 52);
059: }
060:
061: base64Alphabet['+'] = 62;
062: base64Alphabet['/'] = 63;
063:
064: for (int i = 0; i <= 25; i++)
065: lookUpBase64Alphabet[i] = (byte) ('A' + i);
066:
067: for (int i = 26, j = 0; i <= 51; i++, j++)
068: lookUpBase64Alphabet[i] = (byte) ('a' + j);
069:
070: for (int i = 52, j = 0; i <= 61; i++, j++)
071: lookUpBase64Alphabet[i] = (byte) ('0' + j);
072:
073: }
074:
075: static boolean isBase64(byte octect) {
076: //shall we ignore white space? JEFF??
077: return (octect == PAD || base64Alphabet[octect] != -1);
078: }
079:
080: static boolean isArrayByteBase64(byte[] arrayOctect) {
081: int length = arrayOctect.length;
082: if (length == 0)
083: return false;
084: for (int i = 0; i < length; i++) {
085: if (Base64.isBase64(arrayOctect[i]) == false)
086: return false;
087: }
088: return true;
089: }
090:
091: /**
092: * Encodes hex octects into Base64
093: *
094: * @param binaryData Array containing binaryData
095: * @return Encoded Base64 array
096: */
097: public static byte[] encode(byte[] binaryData) {
098: int lengthDataBits = binaryData.length * EIGHTBIT;
099: int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
100: int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
101: byte encodedData[] = null;
102:
103: if (fewerThan24bits != 0) //data not divisible by 24 bit
104: encodedData = new byte[(numberTriplets + 1) * 4];
105: else
106: // 16 or 8 bit
107: encodedData = new byte[numberTriplets * 4];
108:
109: byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
110:
111: int encodedIndex = 0;
112: int dataIndex = 0;
113: int i = 0;
114: for (i = 0; i < numberTriplets; i++) {
115:
116: dataIndex = i * 3;
117: b1 = binaryData[dataIndex];
118: b2 = binaryData[dataIndex + 1];
119: b3 = binaryData[dataIndex + 2];
120:
121: l = (byte) (b2 & 0x0f);
122: k = (byte) (b1 & 0x03);
123:
124: encodedIndex = i * 4;
125: encodedData[encodedIndex] = lookUpBase64Alphabet[b1 >> 2];
126: encodedData[encodedIndex + 1] = lookUpBase64Alphabet[(b2 >> 4)
127: | (k << 4)];
128: encodedData[encodedIndex + 2] = lookUpBase64Alphabet[(l << 2)
129: | (b3 >> 6)];
130: encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
131: }
132:
133: // form integral number of 6-bit groups
134: dataIndex = i * 3;
135: encodedIndex = i * 4;
136: if (fewerThan24bits == EIGHTBIT) {
137: b1 = binaryData[dataIndex];
138: k = (byte) (b1 & 0x03);
139: encodedData[encodedIndex] = lookUpBase64Alphabet[b1 >> 2];
140: encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
141: encodedData[encodedIndex + 2] = PAD;
142: encodedData[encodedIndex + 3] = PAD;
143: } else if (fewerThan24bits == SIXTEENBIT) {
144:
145: b1 = binaryData[dataIndex];
146: b2 = binaryData[dataIndex + 1];
147: l = (byte) (b2 & 0x0f);
148: k = (byte) (b1 & 0x03);
149: encodedData[encodedIndex] = lookUpBase64Alphabet[b1 >> 2];
150: encodedData[encodedIndex + 1] = lookUpBase64Alphabet[(b2 >> 4)
151: | (k << 4)];
152: encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
153: encodedData[encodedIndex + 3] = PAD;
154: }
155: return encodedData;
156: }
157:
158: /**
159: * Decodes Base64 data into octects
160: *
161: * @param binaryData Byte array containing Base64 data
162: * @return Array containind decoded data.
163: */
164: public byte[] decode(byte[] base64Data) {
165: int numberQuadruple = base64Data.length / FOURBYTE;
166: byte decodedData[] = null;
167: byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
168:
169: // Throw away anything not in base64Data
170: // Adjust size
171:
172: int encodedIndex = 0;
173: int dataIndex = 0;
174: decodedData = new byte[numberQuadruple * 3 + 1];
175:
176: for (int i = 0; i < numberQuadruple; i++) {
177: dataIndex = i * 4;
178: marker0 = base64Data[dataIndex + 2];
179: marker1 = base64Data[dataIndex + 3];
180:
181: b1 = base64Alphabet[base64Data[dataIndex]];
182: b2 = base64Alphabet[base64Data[dataIndex + 1]];
183:
184: if (marker0 != PAD && marker1 != PAD) { //No PAD e.g 3cQl
185: b3 = base64Alphabet[marker0];
186: b4 = base64Alphabet[marker1];
187:
188: decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
189: decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
190: decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
191: } else if (marker0 == PAD) { //Two PAD e.g. 3c[Pad][Pad]
192: decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
193: decodedData[encodedIndex + 1] = (byte) ((b2 & 0xf) << 4);
194: decodedData[encodedIndex + 2] = (byte) 0;
195: } else if (marker1 == PAD) { //One PAD e.g. 3cQ[Pad]
196: b3 = base64Alphabet[marker0];
197:
198: decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
199: decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
200: decodedData[encodedIndex + 2] = (byte) (b3 << 6);
201: }
202: encodedIndex += 3;
203: }
204: return decodedData;
205:
206: }
207:
208: static final int base64[] = { 64, 64, 64, 64, 64, 64, 64, 64, 64,
209: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
210: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
211: 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57,
212: 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4,
213: 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
214: 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29,
215: 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
216: 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, 64, 64, 64,
217: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
218: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
219: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
220: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
221: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
222: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
223: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
224: 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
225: 64, 64, 64, 64, 64 };
226:
227: public static String base64Decode(String orig) {
228: char chars[] = orig.toCharArray();
229: StringBuffer sb = new StringBuffer();
230: int i = 0;
231:
232: int shift = 0; // # of excess bits stored in accum
233: int acc = 0;
234:
235: for (i = 0; i < chars.length; i++) {
236: int v = base64[chars[i] & 0xFF];
237:
238: if (v >= 64) {
239: if (chars[i] != '=')
240: System.out.println("Wrong char in base64: "
241: + chars[i]);
242: } else {
243: acc = (acc << 6) | v;
244: shift += 6;
245: if (shift >= 8) {
246: shift -= 8;
247: sb.append((char) ((acc >> shift) & 0xff));
248: }
249: }
250: }
251: return sb.toString();
252: }
253:
254: }
|