001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.core.misc;
066:
067: /**
068: * Proprietary Base64-like encoding class that makes sure there are no special
069: * characters that are "illegal" to cookies.
070: *
071: * @author Michael Rimov
072: */
073: public class CookieBase64 {
074: public CookieBase64() {
075: }
076:
077: static final private int bytesPerLine = 80; // number of bytes per line
078:
079: /* This array maps the characters to their 6 bit values */
080: private final static char[] vec = { 'A', 'B', 'C', 'D', 'E', 'F',
081: 'G', 'H', // 0
082: 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 1
083: 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 2
084: 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 3
085: 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 4
086: 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 5
087: 'w', 'x', 'y', 'z', '0', '1', '2', '3', // 6
088: '4', '5', '6', '7', '8', '9', ',', '.' // 7
089: };
090: private final static byte padding = (byte) '=';
091:
092: /**
093: * @param inByte
094: * @return
095: */
096: static private byte convertToNumber(byte inByte) {
097: if (inByte >= 'A' && inByte <= 'Z') {
098: return (byte) (inByte - 'A');
099: }
100: if (inByte >= 'a' && inByte <= 'z') {
101: return (byte) (inByte - 'a' + 26);
102: }
103: if (inByte >= '0' && inByte <= '9') {
104: return (byte) (inByte - '0' + 52);
105: }
106: if (inByte == ',') {
107: return (62);
108: }
109: if (inByte == '.') {
110: return (63);
111: }
112:
113: return (-1);
114: } /* convertToNumber(byte) */
115:
116: /**
117: * decode - Decodes a Base64 encoded string back into its original
118: * binary format. If the data is not a proper base64 encoded string,
119: * it might throw an ArrayIndexOutOfBoundsException.
120: *
121: * @param data the data to decode
122: * @return
123: */
124: static private byte[] decode(String data)
125: throws IllegalArgumentException {
126:
127: //Check for NULL
128: if (data == null) {
129: throw new IllegalArgumentException(
130: "Base64.decode: data must not be null");
131: }
132: //Check to see if data is proper length
133: if (data.length() % 4 != 0) {
134: throw new IllegalArgumentException(
135: "Base64.decode: data it not of proper length");
136: }
137:
138: byte[] inputBuffer = data.getBytes();
139: int validInputCount = 0;
140: byte[] inBuffer = new byte[inputBuffer.length];
141: int dataLength = inputBuffer.length;
142:
143: //We use the same input and output buffer since
144: // the value will be the same
145: //
146: //Preprocess -- Strip the LF's et al
147: //
148: int i;
149:
150: for (i = 0; i < dataLength; i++) {
151: byte temp = convertToNumber(inputBuffer[i]);
152:
153: if (temp >= 0) {
154: inBuffer[i] = temp;
155: validInputCount++;
156: }
157: }
158:
159: byte[] outBuffer = new byte[dataLength];
160: int startOut = 0;
161: int startIn = 0;
162:
163: while (validInputCount > startIn) {
164: int dataLen = validInputCount;
165:
166: if (dataLen - startIn > 3) {
167: outBuffer[startOut] = (byte) ((inBuffer[startIn] << 2) + (inBuffer[startIn + 1] >>> 4));
168: outBuffer[startOut + 1] = (byte) ((inBuffer[startIn + 1] << 4) + (inBuffer[startIn + 2] >>> 2));
169: outBuffer[startOut + 2] = (byte) ((inBuffer[startIn + 2] << 6) + (inBuffer[startIn + 3]));
170: startOut += 3;
171: startIn += 4;
172: } else if (dataLen - startIn > 2) {
173: outBuffer[startOut] = (byte) ((inBuffer[startIn] << 2) + (inBuffer[startIn + 1] >>> 4));
174: outBuffer[startOut + 1] = (byte) ((inBuffer[startIn + 1] << 4) + (inBuffer[startIn + 2] >>> 2));
175: startOut += 2;
176: startIn += 3;
177: } else if (dataLen - startIn > 1) {
178: outBuffer[startOut] = (byte) ((inBuffer[startIn] << 2) + (inBuffer[startIn + 1] >>> 4));
179: startOut += 1;
180: startIn += 2;
181: } else {
182: throw new IllegalStateException(
183: "com.jcorporate.expresso.core.misc."
184: + "Base64.Decode: Corrupt Input Data");
185: }
186: }
187:
188: //Copy the final bytes over to a real output array
189: byte[] finalOutput = new byte[startOut];
190:
191: for (i = 0; i < startOut; i++) {
192: finalOutput[i] = outBuffer[i];
193: }
194:
195: inBuffer = null;
196: outBuffer = null;
197:
198: return finalOutput;
199: } /* decode(String) */
200:
201: /**
202: * <B>Note: this function does not process stricly compliant Base64
203: * code. To process strictly compliant Base64 encoded strings, use encode
204: * and decode functions with padding</B>
205: * <p/>
206: * Decodes a Base64 encoded string back into its original binary format.
207: * The only difference from decode is that this function will bad the
208: * end with as many ='s as necessary to make things work properly.
209: *
210: * @param data the Base64 encoded string
211: * @return the byte array of the original data.
212: * @throws IllegalArgumentException if the input data is null or zero bytes.
213: */
214: static public byte[] decodeNoPadding(String data)
215: throws IllegalArgumentException {
216: String myName = "Base64.decodeNoPadding";
217:
218: if (data == null) {
219: throw new IllegalArgumentException(myName
220: + " parameter 'data'" + " must not be null");
221: }
222: if (data.length() == 0) {
223: throw new IllegalArgumentException(myName
224: + " parameter 'data'"
225: + " must not be greater than zero length");
226: }
227: //Append as many zeros as necessary to make things work.
228: for (; data.length() % 4 != 0; data = data + "=") {
229: ;
230: }
231:
232: return decode(data);
233: } /* decodeNoPadding(String) */
234:
235: /**
236: * encode - Encodes a binary byte array into an Ascii String (including 80
237: * column line wrap.
238: *
239: * @param inBuffer[] the data to encode
240: * @return
241: */
242: static private String encode(byte[] inBuffer)
243: throws IllegalArgumentException {
244: if (inBuffer.length == 0) {
245: throw new IllegalArgumentException("Base64.encode: "
246: + "inBuffer must be > zero bytes in length");
247: }
248:
249: int dataSize = inBuffer.length;
250: int startIn = 0;
251: int startOut = 0;
252:
253: //Create an output buffer that's twice the size of the input buffer
254: //that way we have enough room for sure
255: byte[] outBuffer;
256:
257: if (dataSize < 4) {
258: outBuffer = new byte[4];
259: } else {
260: outBuffer = new byte[dataSize * 2];
261: }
262: //Iteratate
263: while (startIn < dataSize) {
264: int dataLen = inBuffer.length;
265: byte a;
266: byte b;
267: byte c;
268:
269: //Check for linewrap
270: if ((startOut % bytesPerLine) + 4 > bytesPerLine) {
271: outBuffer[startOut] = (byte) '\r';
272: outBuffer[startOut + 1] = (byte) '\n';
273: startOut += 2;
274: }
275: if (dataLen - startIn > 2) {
276: a = inBuffer[startIn];
277: b = inBuffer[startIn + 1];
278: c = inBuffer[startIn + 2];
279: outBuffer[startOut] = (byte) vec[(a >>> 2) & 0x3F];
280: outBuffer[startOut + 1] = (byte) vec[((a << 4) & 0x30)
281: + ((b >>> 4) & 0xf)];
282: outBuffer[startOut + 2] = (byte) vec[((b << 2) & 0x3c)
283: + ((c >>> 6) & 0x3)];
284: outBuffer[startOut + 3] = (byte) vec[c & 0x3F];
285: startOut += 4;
286: startIn += 3;
287: } else if (dataLen - startIn == 1) {
288: a = inBuffer[startIn];
289: b = 0;
290: c = 0;
291: outBuffer[startOut] = (byte) vec[(a >>> 2) & 0x3F];
292: outBuffer[startOut + 1] = (byte) vec[((a << 4) & 0x30)
293: + ((b >>> 4) & 0xf)];
294: outBuffer[startOut + 2] = padding;
295: outBuffer[startOut + 3] = padding;
296: startOut += 4;
297: startIn += 2;
298: } else if (dataLen - startIn == 2) {
299: a = inBuffer[startIn];
300: b = inBuffer[startIn + 1];
301: c = 0;
302: outBuffer[startOut] = (byte) vec[(a >>> 2) & 0x3F];
303: outBuffer[startOut + 1] = (byte) vec[((a << 4) & 0x30)
304: + ((b >>> 4) & 0xf)];
305: outBuffer[startOut + 2] = (byte) vec[((b << 2) & 0x3c)
306: + ((c >>> 6) & 0x3)];
307: outBuffer[startOut + 3] = padding;
308: startOut += 4;
309: startIn += 2;
310: }
311: }
312:
313: return new String(outBuffer, 0, startOut);
314: } /* encode(byte) */
315:
316: /* */
317: /* */
318: /* Encoding Part */
319: /* */
320: /* */
321: /**
322: * <B>Note: this function does not process stricly compliant Base64
323: * code. To process strictly compliant Base64 encoded strings, use encode
324: * and decode functions with padding</B>
325: * <p/>
326: * Encodes a binary bite array into Base64 coding. The difference between
327: * this and the other encode function, is that this function strips all
328: * padding from the final result before returning
329: *
330: * @param inBuffer[] the byte array to encode.
331: * @return a string that is the Base64 equiv of the input data without
332: * padding characters
333: * @throws IllegalArgumentException if the input data is null or zero bytes.
334: */
335: static public String encodeNoPadding(byte[] inBuffer)
336: throws IllegalArgumentException {
337: String stringWithPadding = encode(inBuffer);
338: int equalsPlacement = stringWithPadding.indexOf((int) '=');
339:
340: return (equalsPlacement != -1) ? (stringWithPadding.substring(
341: 0, equalsPlacement)) : (stringWithPadding);
342: } /* encodeNoPaggding(byte) */
343:
344: }
|