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