0001: /*
0002: * The contents of this file are subject to the terms
0003: * of the Common Development and Distribution License
0004: * (the License). You may not use this file except in
0005: * compliance with the License.
0006: *
0007: * You can obtain a copy of the license at
0008: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
0009: * See the License for the specific language governing
0010: * permissions and limitations under the License.
0011: *
0012: * When distributing Covered Code, include this CDDL
0013: * Header Notice in each file and include the License file
0014: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
0015: * If applicable, add the following below the CDDL Header,
0016: * with the fields enclosed by brackets [] replaced by
0017: * you own identifying information:
0018: * "Portions Copyrighted [year] [name of copyright owner]"
0019: *
0020: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
0021: */
0022:
0023: /*
0024: * Copyright 1999-2004 The Apache Software Foundation.
0025: *
0026: * Licensed under the Apache License, Version 2.0 (the "License");
0027: * you may not use this file except in compliance with the License.
0028: * You may obtain a copy of the License at
0029: *
0030: * http://www.apache.org/licenses/LICENSE-2.0
0031: *
0032: * Unless required by applicable law or agreed to in writing, software
0033: * distributed under the License is distributed on an "AS IS" BASIS,
0034: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0035: * See the License for the specific language governing permissions and
0036: * limitations under the License.
0037: *
0038: */
0039: package com.sun.xml.wss.impl.misc;
0040:
0041: import java.io.IOException;
0042: import java.io.InputStream;
0043: import java.io.OutputStream;
0044:
0045: import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
0046:
0047: /**
0048: * Implementation of MIME's Base64 encoding and decoding conversions.
0049: * Optimized code. (raw version taken from oreilly.jonathan.util,
0050: * and currently com.sun.org.apache.xerces.internal.ds.util.Base64)
0051: *
0052: * @author Raul Benito(Of the xerces copy, and little adaptations).
0053: * @author Anli Shundi
0054: * @author Christian Geuer-Pollmann
0055: * @see <A HREF="ftp://ftp.isi.edu/in-notes/rfc2045.txt">RFC 2045</A>
0056: * @see com.sun.org.apache.xml.internal.security.transforms.implementations.TransformBase64Decode
0057: */
0058: public class Base64 {
0059:
0060: /** Field BASE64DEFAULTLENGTH */
0061: public static final int BASE64DEFAULTLENGTH = 76;
0062:
0063: /** Field _base64length */
0064: //static int _base64length = Base64.BASE64DEFAULTLENGTH;
0065: private Base64() {
0066: // we don't allow instantiation
0067: }
0068:
0069: static private final int BASELENGTH = 255;
0070: static private final int LOOKUPLENGTH = 64;
0071: static private final int TWENTYFOURBITGROUP = 24;
0072: static private final int EIGHTBIT = 8;
0073: static private final int SIXTEENBIT = 16;
0074: static private final int FOURBYTE = 4;
0075: static private final int SIGN = -128;
0076: static private final char PAD = '=';
0077: static private final boolean fDebug = false;
0078: static final private byte[] base64Alphabet = new byte[BASELENGTH];
0079: static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
0080:
0081: static {
0082:
0083: for (int i = 0; i < BASELENGTH; i++) {
0084: base64Alphabet[i] = -1;
0085: }
0086: for (int i = 'Z'; i >= 'A'; i--) {
0087: base64Alphabet[i] = (byte) (i - 'A');
0088: }
0089: for (int i = 'z'; i >= 'a'; i--) {
0090: base64Alphabet[i] = (byte) (i - 'a' + 26);
0091: }
0092:
0093: for (int i = '9'; i >= '0'; i--) {
0094: base64Alphabet[i] = (byte) (i - '0' + 52);
0095: }
0096:
0097: base64Alphabet['+'] = 62;
0098: base64Alphabet['/'] = 63;
0099:
0100: for (int i = 0; i <= 25; i++)
0101: lookUpBase64Alphabet[i] = (char) ('A' + i);
0102:
0103: for (int i = 26, j = 0; i <= 51; i++, j++)
0104: lookUpBase64Alphabet[i] = (char) ('a' + j);
0105:
0106: for (int i = 52, j = 0; i <= 61; i++, j++)
0107: lookUpBase64Alphabet[i] = (char) ('0' + j);
0108: lookUpBase64Alphabet[62] = '+';
0109: lookUpBase64Alphabet[63] = '/';
0110:
0111: }
0112:
0113: protected static final boolean isWhiteSpace(byte octect) {
0114: return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
0115: }
0116:
0117: protected static final boolean isPad(byte octect) {
0118: return (octect == PAD);
0119: }
0120:
0121: /**
0122: * Encodes hex octects into Base64
0123: *
0124: * @param binaryData Array containing binaryData
0125: * @return Encoded Base64 array
0126: */
0127:
0128: public char[] encodeData(byte[] binaryData) {
0129: return encodeData(binaryData, 2046);
0130: //BASE64DEFAULTLENGTH);
0131: }
0132:
0133: /**
0134: * Encode a byte array in Base64 format and return an optionally
0135: * wrapped line.
0136: *
0137: * @param binaryData <code>byte[]</code> data to be encoded
0138: * @param length <code>int<code> length of wrapped lines; No wrapping if less than 4.
0139: * @return a <code>String</code> with encoded data
0140: */
0141: public static char[] encodeData(byte[] binaryData, int length) {
0142:
0143: if (length < 4) {
0144: length = Integer.MAX_VALUE;
0145: }
0146:
0147: if (binaryData == null)
0148: return null;
0149:
0150: int lengthDataBits = binaryData.length * EIGHTBIT;
0151: if (lengthDataBits == 0) {
0152: return "".toCharArray();
0153:
0154: }
0155:
0156: int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
0157: int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
0158: int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1
0159: : numberTriplets;
0160: int quartesPerLine = length / 4;
0161: int numberLines = (numberQuartet - 1) / quartesPerLine;
0162: char encodedData[] = null;
0163:
0164: encodedData = new char[numberQuartet * 4 + numberLines];
0165:
0166: byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
0167:
0168: int encodedIndex = 0;
0169: int dataIndex = 0;
0170: int i = 0;
0171: if (fDebug) {
0172: System.out
0173: .println("number of triplets = " + numberTriplets);
0174: }
0175:
0176: for (int line = 0; line < numberLines; line++) {
0177: for (int quartet = 0; quartet < 19; quartet++) {
0178: b1 = binaryData[dataIndex++];
0179: b2 = binaryData[dataIndex++];
0180: b3 = binaryData[dataIndex++];
0181:
0182: if (fDebug) {
0183: System.out.println("b1= " + b1 + ", b2= " + b2
0184: + ", b3= " + b3);
0185: }
0186:
0187: l = (byte) (b2 & 0x0f);
0188: k = (byte) (b1 & 0x03);
0189:
0190: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0191: : (byte) ((b1) >> 2 ^ 0xc0);
0192:
0193: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0194: : (byte) ((b2) >> 4 ^ 0xf0);
0195: byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
0196: : (byte) ((b3) >> 6 ^ 0xfc);
0197:
0198: if (fDebug) {
0199: System.out.println("val2 = " + val2);
0200: System.out.println("k4 = " + (k << 4));
0201: System.out.println("vak = " + (val2 | (k << 4)));
0202: }
0203:
0204: encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
0205: encodedData[encodedIndex++] = lookUpBase64Alphabet[val2
0206: | (k << 4)];
0207: encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2)
0208: | val3];
0209: encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
0210:
0211: i++;
0212: }
0213: encodedData[encodedIndex++] = 0xa;
0214: }
0215:
0216: for (; i < numberTriplets; i++) {
0217: b1 = binaryData[dataIndex++];
0218: b2 = binaryData[dataIndex++];
0219: b3 = binaryData[dataIndex++];
0220:
0221: if (fDebug) {
0222: System.out.println("b1= " + b1 + ", b2= " + b2
0223: + ", b3= " + b3);
0224: }
0225:
0226: l = (byte) (b2 & 0x0f);
0227: k = (byte) (b1 & 0x03);
0228:
0229: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0230: : (byte) ((b1) >> 2 ^ 0xc0);
0231:
0232: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0233: : (byte) ((b2) >> 4 ^ 0xf0);
0234: byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
0235: : (byte) ((b3) >> 6 ^ 0xfc);
0236:
0237: if (fDebug) {
0238: System.out.println("val2 = " + val2);
0239: System.out.println("k4 = " + (k << 4));
0240: System.out.println("vak = " + (val2 | (k << 4)));
0241: }
0242:
0243: encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
0244: encodedData[encodedIndex++] = lookUpBase64Alphabet[val2
0245: | (k << 4)];
0246: encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2)
0247: | val3];
0248: encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
0249: }
0250:
0251: // form integral number of 6-bit groups
0252: if (fewerThan24bits == EIGHTBIT) {
0253: b1 = binaryData[dataIndex];
0254: k = (byte) (b1 & 0x03);
0255: if (fDebug) {
0256: System.out.println("b1=" + b1);
0257: System.out.println("b1<<2 = " + (b1 >> 2));
0258: }
0259: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0260: : (byte) ((b1) >> 2 ^ 0xc0);
0261: encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
0262: encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
0263: encodedData[encodedIndex++] = PAD;
0264: encodedData[encodedIndex++] = PAD;
0265: } else if (fewerThan24bits == SIXTEENBIT) {
0266: b1 = binaryData[dataIndex];
0267: b2 = binaryData[dataIndex + 1];
0268: l = (byte) (b2 & 0x0f);
0269: k = (byte) (b1 & 0x03);
0270:
0271: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0272: : (byte) ((b1) >> 2 ^ 0xc0);
0273: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0274: : (byte) ((b2) >> 4 ^ 0xf0);
0275:
0276: encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
0277: encodedData[encodedIndex++] = lookUpBase64Alphabet[val2
0278: | (k << 4)];
0279: encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
0280: encodedData[encodedIndex++] = PAD;
0281: }
0282:
0283: //encodedData[encodedIndex] = 0xa;
0284:
0285: return encodedData;
0286: }
0287:
0288: public static String encode(byte[] binaryData, int length) {
0289:
0290: if (length < 4) {
0291: length = Integer.MAX_VALUE;
0292: }
0293:
0294: if (binaryData == null)
0295: return null;
0296:
0297: int lengthDataBits = binaryData.length * EIGHTBIT;
0298: if (lengthDataBits == 0) {
0299: return "";
0300: }
0301:
0302: int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
0303: int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
0304: int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1
0305: : numberTriplets;
0306: int quartesPerLine = length / 4;
0307: int numberLines = (numberQuartet - 1) / quartesPerLine;
0308: char encodedData[] = null;
0309:
0310: encodedData = new char[numberQuartet * 4 + numberLines];
0311:
0312: byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
0313:
0314: int encodedIndex = 0;
0315: int dataIndex = 0;
0316: int i = 0;
0317: if (fDebug) {
0318: System.out
0319: .println("number of triplets = " + numberTriplets);
0320: }
0321:
0322: for (int line = 0; line < numberLines; line++) {
0323: for (int quartet = 0; quartet < 19; quartet++) {
0324: b1 = binaryData[dataIndex++];
0325: b2 = binaryData[dataIndex++];
0326: b3 = binaryData[dataIndex++];
0327:
0328: if (fDebug) {
0329: System.out.println("b1= " + b1 + ", b2= " + b2
0330: + ", b3= " + b3);
0331: }
0332:
0333: l = (byte) (b2 & 0x0f);
0334: k = (byte) (b1 & 0x03);
0335:
0336: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0337: : (byte) ((b1) >> 2 ^ 0xc0);
0338:
0339: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0340: : (byte) ((b2) >> 4 ^ 0xf0);
0341: byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
0342: : (byte) ((b3) >> 6 ^ 0xfc);
0343:
0344: if (fDebug) {
0345: System.out.println("val2 = " + val2);
0346: System.out.println("k4 = " + (k << 4));
0347: System.out.println("vak = " + (val2 | (k << 4)));
0348: }
0349:
0350: encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
0351: encodedData[encodedIndex++] = lookUpBase64Alphabet[val2
0352: | (k << 4)];
0353: encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2)
0354: | val3];
0355: encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
0356:
0357: i++;
0358: }
0359: encodedData[encodedIndex++] = 0xa;
0360: }
0361:
0362: for (; i < numberTriplets; i++) {
0363: b1 = binaryData[dataIndex++];
0364: b2 = binaryData[dataIndex++];
0365: b3 = binaryData[dataIndex++];
0366:
0367: if (fDebug) {
0368: System.out.println("b1= " + b1 + ", b2= " + b2
0369: + ", b3= " + b3);
0370: }
0371:
0372: l = (byte) (b2 & 0x0f);
0373: k = (byte) (b1 & 0x03);
0374:
0375: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0376: : (byte) ((b1) >> 2 ^ 0xc0);
0377:
0378: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0379: : (byte) ((b2) >> 4 ^ 0xf0);
0380: byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
0381: : (byte) ((b3) >> 6 ^ 0xfc);
0382:
0383: if (fDebug) {
0384: System.out.println("val2 = " + val2);
0385: System.out.println("k4 = " + (k << 4));
0386: System.out.println("vak = " + (val2 | (k << 4)));
0387: }
0388:
0389: encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
0390: encodedData[encodedIndex++] = lookUpBase64Alphabet[val2
0391: | (k << 4)];
0392: encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2)
0393: | val3];
0394: encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
0395: }
0396:
0397: // form integral number of 6-bit groups
0398: if (fewerThan24bits == EIGHTBIT) {
0399: b1 = binaryData[dataIndex];
0400: k = (byte) (b1 & 0x03);
0401: if (fDebug) {
0402: System.out.println("b1=" + b1);
0403: System.out.println("b1<<2 = " + (b1 >> 2));
0404: }
0405: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0406: : (byte) ((b1) >> 2 ^ 0xc0);
0407: encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
0408: encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
0409: encodedData[encodedIndex++] = PAD;
0410: encodedData[encodedIndex++] = PAD;
0411: } else if (fewerThan24bits == SIXTEENBIT) {
0412: b1 = binaryData[dataIndex];
0413: b2 = binaryData[dataIndex + 1];
0414: l = (byte) (b2 & 0x0f);
0415: k = (byte) (b1 & 0x03);
0416:
0417: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0418: : (byte) ((b1) >> 2 ^ 0xc0);
0419: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0420: : (byte) ((b2) >> 4 ^ 0xf0);
0421:
0422: encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
0423: encodedData[encodedIndex++] = lookUpBase64Alphabet[val2
0424: | (k << 4)];
0425: encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
0426: encodedData[encodedIndex++] = PAD;
0427: }
0428:
0429: //encodedData[encodedIndex] = 0xa;
0430:
0431: return new String(encodedData);
0432: }
0433:
0434: public static String encode(byte[] binaryData) {
0435: //Use 2K as the default length
0436: return encode(binaryData, 2048);
0437: }
0438:
0439: public static void encodeToStream(byte[] binaryData, int length,
0440: OutputStream stream) throws IOException {
0441: encodeToStream(binaryData, 0, length, stream);
0442: }
0443:
0444: public static void encodeToStream(byte[] binaryData, int offset,
0445: int length, OutputStream stream) throws IOException {
0446:
0447: if (length < 4) {
0448: length = Integer.MAX_VALUE;
0449: }
0450:
0451: if (binaryData == null)
0452: return;
0453:
0454: int lengthDataBits = length * EIGHTBIT;
0455: if (lengthDataBits == 0) {
0456: return;
0457: }
0458:
0459: int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
0460: int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
0461: int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1
0462: : numberTriplets;
0463: int quartesPerLine = length / 4;
0464: int numberLines = (numberQuartet - 1) / quartesPerLine;
0465: // char encodedData[] = null;
0466:
0467: // encodedData = new char[numberQuartet*4+numberLines];
0468:
0469: byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
0470:
0471: int encodedIndex = 0;
0472: int dataIndex = offset;
0473: int i = 0;
0474: if (fDebug) {
0475: System.out
0476: .println("number of triplets = " + numberTriplets);
0477: }
0478:
0479: for (int line = 0; line < numberLines; line++) {
0480: for (int quartet = 0; quartet < 19; quartet++) {
0481: b1 = binaryData[dataIndex++];
0482: b2 = binaryData[dataIndex++];
0483: b3 = binaryData[dataIndex++];
0484:
0485: if (fDebug) {
0486: System.out.println("b1= " + b1 + ", b2= " + b2
0487: + ", b3= " + b3);
0488: }
0489:
0490: l = (byte) (b2 & 0x0f);
0491: k = (byte) (b1 & 0x03);
0492:
0493: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0494: : (byte) ((b1) >> 2 ^ 0xc0);
0495:
0496: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0497: : (byte) ((b2) >> 4 ^ 0xf0);
0498: byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
0499: : (byte) ((b3) >> 6 ^ 0xfc);
0500:
0501: if (fDebug) {
0502: System.out.println("val2 = " + val2);
0503: System.out.println("k4 = " + (k << 4));
0504: System.out.println("vak = " + (val2 | (k << 4)));
0505: }
0506:
0507: /* encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
0508: encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
0509: encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
0510: encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];*/
0511: stream.write(lookUpBase64Alphabet[val1]);
0512: stream.write(lookUpBase64Alphabet[val2 | (k << 4)]);
0513: stream.write(lookUpBase64Alphabet[(l << 2) | val3]);
0514: stream.write(lookUpBase64Alphabet[b3 & 0x3f]);
0515: i++;
0516: }
0517: //encodedData[encodedIndex++] = 0xa;
0518: stream.write(0xa);
0519: }
0520:
0521: for (; i < numberTriplets; i++) {
0522: b1 = binaryData[dataIndex++];
0523: b2 = binaryData[dataIndex++];
0524: b3 = binaryData[dataIndex++];
0525:
0526: if (fDebug) {
0527: System.out.println("b1= " + b1 + ", b2= " + b2
0528: + ", b3= " + b3);
0529: }
0530:
0531: l = (byte) (b2 & 0x0f);
0532: k = (byte) (b1 & 0x03);
0533:
0534: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0535: : (byte) ((b1) >> 2 ^ 0xc0);
0536:
0537: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0538: : (byte) ((b2) >> 4 ^ 0xf0);
0539: byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
0540: : (byte) ((b3) >> 6 ^ 0xfc);
0541:
0542: if (fDebug) {
0543: System.out.println("val2 = " + val2);
0544: System.out.println("k4 = " + (k << 4));
0545: System.out.println("vak = " + (val2 | (k << 4)));
0546: }
0547: stream.write(lookUpBase64Alphabet[val1]);
0548: stream.write(lookUpBase64Alphabet[val2 | (k << 4)]);
0549: stream.write(lookUpBase64Alphabet[(l << 2) | val3]);
0550: stream.write(lookUpBase64Alphabet[b3 & 0x3f]);
0551: /* encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
0552: encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
0553: encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
0554: encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];*/
0555: }
0556:
0557: // form integral number of 6-bit groups
0558: if (fewerThan24bits == EIGHTBIT) {
0559: b1 = binaryData[dataIndex];
0560: k = (byte) (b1 & 0x03);
0561: if (fDebug) {
0562: System.out.println("b1=" + b1);
0563: System.out.println("b1<<2 = " + (b1 >> 2));
0564: }
0565: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0566: : (byte) ((b1) >> 2 ^ 0xc0);
0567: /* encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
0568: encodedData[encodedIndex++] = lookUpBase64Alphabet[ k<<4 ];
0569: encodedData[encodedIndex++] = PAD;
0570: encodedData[encodedIndex++] = PAD;*/
0571: stream.write(lookUpBase64Alphabet[val1]);
0572: stream.write(lookUpBase64Alphabet[k << 4]);
0573: stream.write(PAD);
0574: stream.write(PAD);
0575: } else if (fewerThan24bits == SIXTEENBIT) {
0576: b1 = binaryData[dataIndex];
0577: b2 = binaryData[dataIndex + 1];
0578: l = (byte) (b2 & 0x0f);
0579: k = (byte) (b1 & 0x03);
0580:
0581: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0582: : (byte) ((b1) >> 2 ^ 0xc0);
0583: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0584: : (byte) ((b2) >> 4 ^ 0xf0);
0585:
0586: /* encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
0587: encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
0588: encodedData[encodedIndex++] = lookUpBase64Alphabet[ l<<2 ];
0589: encodedData[encodedIndex++] = PAD;
0590: */
0591: stream.write(lookUpBase64Alphabet[val1]);
0592: stream.write(lookUpBase64Alphabet[val2 | (k << 4)]);
0593: stream.write(lookUpBase64Alphabet[l << 2]);
0594: stream.write(PAD);
0595: }
0596:
0597: //encodedData[encodedIndex] = 0xa;
0598:
0599: //return new String(encodedData);
0600: }
0601:
0602: public static void encodeToStream(ByteArray binaryData, int length,
0603: OutputStream stream) throws IOException {
0604:
0605: if (length < 4) {
0606: length = Integer.MAX_VALUE;
0607: }
0608:
0609: if (binaryData == null)
0610: return;
0611:
0612: int lengthDataBits = binaryData.length * EIGHTBIT;
0613: if (lengthDataBits == 0) {
0614: return;
0615: }
0616:
0617: int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
0618: int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
0619: int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1
0620: : numberTriplets;
0621: int quartesPerLine = length / 4;
0622: int numberLines = (numberQuartet - 1) / quartesPerLine;
0623: // char encodedData[] = null;
0624:
0625: // encodedData = new char[numberQuartet*4+numberLines];
0626:
0627: byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
0628:
0629: int encodedIndex = 0;
0630: int dataIndex = 0;
0631: int i = 0;
0632: if (fDebug) {
0633: System.out
0634: .println("number of triplets = " + numberTriplets);
0635: }
0636:
0637: for (int line = 0; line < numberLines; line++) {
0638: for (int quartet = 0; quartet < 19; quartet++) {
0639: b1 = binaryData.byteAt(dataIndex++);
0640: b2 = binaryData.byteAt(dataIndex++);
0641: b3 = binaryData.byteAt(dataIndex++);
0642:
0643: if (fDebug) {
0644: System.out.println("b1= " + b1 + ", b2= " + b2
0645: + ", b3= " + b3);
0646: }
0647:
0648: l = (byte) (b2 & 0x0f);
0649: k = (byte) (b1 & 0x03);
0650:
0651: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0652: : (byte) ((b1) >> 2 ^ 0xc0);
0653:
0654: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0655: : (byte) ((b2) >> 4 ^ 0xf0);
0656: byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
0657: : (byte) ((b3) >> 6 ^ 0xfc);
0658:
0659: if (fDebug) {
0660: System.out.println("val2 = " + val2);
0661: System.out.println("k4 = " + (k << 4));
0662: System.out.println("vak = " + (val2 | (k << 4)));
0663: }
0664:
0665: /* encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
0666: encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
0667: encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
0668: encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];*/
0669: stream.write(lookUpBase64Alphabet[val1]);
0670: stream.write(lookUpBase64Alphabet[val2 | (k << 4)]);
0671: stream.write(lookUpBase64Alphabet[(l << 2) | val3]);
0672: stream.write(lookUpBase64Alphabet[b3 & 0x3f]);
0673: i++;
0674: }
0675: //encodedData[encodedIndex++] = 0xa;
0676: stream.write(0xa);
0677: }
0678:
0679: for (; i < numberTriplets; i++) {
0680: b1 = binaryData.byteAt(dataIndex++);
0681: b2 = binaryData.byteAt(dataIndex++);
0682: b3 = binaryData.byteAt(dataIndex++);
0683:
0684: if (fDebug) {
0685: System.out.println("b1= " + b1 + ", b2= " + b2
0686: + ", b3= " + b3);
0687: }
0688:
0689: l = (byte) (b2 & 0x0f);
0690: k = (byte) (b1 & 0x03);
0691:
0692: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0693: : (byte) ((b1) >> 2 ^ 0xc0);
0694:
0695: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0696: : (byte) ((b2) >> 4 ^ 0xf0);
0697: byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
0698: : (byte) ((b3) >> 6 ^ 0xfc);
0699:
0700: if (fDebug) {
0701: System.out.println("val2 = " + val2);
0702: System.out.println("k4 = " + (k << 4));
0703: System.out.println("vak = " + (val2 | (k << 4)));
0704: }
0705: stream.write(lookUpBase64Alphabet[val1]);
0706: stream.write(lookUpBase64Alphabet[val2 | (k << 4)]);
0707: stream.write(lookUpBase64Alphabet[(l << 2) | val3]);
0708: stream.write(lookUpBase64Alphabet[b3 & 0x3f]);
0709: /* encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
0710: encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
0711: encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
0712: encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];*/
0713: }
0714:
0715: // form integral number of 6-bit groups
0716: if (fewerThan24bits == EIGHTBIT) {
0717: b1 = binaryData.byteAt(dataIndex);
0718: k = (byte) (b1 & 0x03);
0719: if (fDebug) {
0720: System.out.println("b1=" + b1);
0721: System.out.println("b1<<2 = " + (b1 >> 2));
0722: }
0723: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0724: : (byte) ((b1) >> 2 ^ 0xc0);
0725: /* encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
0726: encodedData[encodedIndex++] = lookUpBase64Alphabet[ k<<4 ];
0727: encodedData[encodedIndex++] = PAD;
0728: encodedData[encodedIndex++] = PAD;*/
0729: stream.write(lookUpBase64Alphabet[val1]);
0730: stream.write(lookUpBase64Alphabet[k << 4]);
0731: stream.write(PAD);
0732: stream.write(PAD);
0733: } else if (fewerThan24bits == SIXTEENBIT) {
0734: b1 = binaryData.byteAt(dataIndex);
0735: b2 = binaryData.byteAt(dataIndex + 1);
0736: l = (byte) (b2 & 0x0f);
0737: k = (byte) (b1 & 0x03);
0738:
0739: byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
0740: : (byte) ((b1) >> 2 ^ 0xc0);
0741: byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
0742: : (byte) ((b2) >> 4 ^ 0xf0);
0743:
0744: /* encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
0745: encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
0746: encodedData[encodedIndex++] = lookUpBase64Alphabet[ l<<2 ];
0747: encodedData[encodedIndex++] = PAD;
0748: */
0749: stream.write(lookUpBase64Alphabet[val1]);
0750: stream.write(lookUpBase64Alphabet[val2 | (k << 4)]);
0751: stream.write(lookUpBase64Alphabet[l << 2]);
0752: stream.write(PAD);
0753: }
0754:
0755: //encodedData[encodedIndex] = 0xa;
0756:
0757: //return new String(encodedData);
0758: }
0759:
0760: /**
0761: * Decodes Base64 data into octects
0762: *
0763: * @param encoded Byte array containing Base64 data
0764: * @return Array containind decoded data.
0765: * @throws Base64DecodingException
0766: */
0767: public final static byte[] decode(String encoded)
0768: throws Base64DecodingException {
0769:
0770: if (encoded == null)
0771: return null;
0772:
0773: return decodeInternal(encoded.getBytes());
0774: }
0775:
0776: public final static byte[] decode(byte[] base64Data)
0777: throws Base64DecodingException {
0778: return decodeInternal(base64Data);
0779: }
0780:
0781: protected final static byte[] decodeInternal(byte[] base64Data)
0782: throws Base64DecodingException {
0783: // remove white spaces
0784: int len = removeWhiteSpace(base64Data);
0785:
0786: if (len % FOURBYTE != 0) {
0787: throw new Base64DecodingException("decoding.divisible.four");
0788: //should be divisible by four
0789: }
0790:
0791: int numberQuadruple = (len / FOURBYTE);
0792:
0793: if (numberQuadruple == 0)
0794: return new byte[0];
0795:
0796: byte decodedData[] = null;
0797: byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
0798:
0799: int i = 0;
0800: int encodedIndex = 0;
0801: int dataIndex = 0;
0802:
0803: //decodedData = new byte[ (numberQuadruple)*3];
0804: dataIndex = (numberQuadruple - 1) * 4;
0805: encodedIndex = (numberQuadruple - 1) * 3;
0806: //first last bits.
0807: b1 = base64Alphabet[base64Data[dataIndex++]];
0808: b2 = base64Alphabet[base64Data[dataIndex++]];
0809: if ((b1 == -1) || (b2 == -1)) {
0810: throw new Base64DecodingException("decoding.general");//if found "no data" just return null
0811: }
0812:
0813: byte d3, d4;
0814: b3 = base64Alphabet[d3 = base64Data[dataIndex++]];
0815: b4 = base64Alphabet[d4 = base64Data[dataIndex++]];
0816: if ((b3 == -1) || (b4 == -1)) {
0817: //Check if they are PAD characters
0818: if (isPad(d3) && isPad(d4)) { //Two PAD e.g. 3c[Pad][Pad]
0819: if ((b2 & 0xf) != 0)//last 4 bits should be zero
0820: throw new Base64DecodingException(
0821: "decoding.general");
0822: decodedData = new byte[encodedIndex + 1];
0823: decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
0824: } else if (!isPad(d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
0825: if ((b3 & 0x3) != 0)//last 2 bits should be zero
0826: throw new Base64DecodingException(
0827: "decoding.general");
0828: decodedData = new byte[encodedIndex + 2];
0829: decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
0830: decodedData[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
0831: } else {
0832: throw new Base64DecodingException("decoding.general");//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
0833: }
0834: } else {
0835: //No PAD e.g 3cQl
0836: decodedData = new byte[encodedIndex + 3];
0837: decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
0838: decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
0839: decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
0840: }
0841: encodedIndex = 0;
0842: dataIndex = 0;
0843: //the begin
0844: for (i = numberQuadruple - 1; i > 0; i--) {
0845: b1 = base64Alphabet[base64Data[dataIndex++]];
0846: b2 = base64Alphabet[base64Data[dataIndex++]];
0847: b3 = base64Alphabet[base64Data[dataIndex++]];
0848: b4 = base64Alphabet[base64Data[dataIndex++]];
0849:
0850: if ((b1 == -1) || (b2 == -1) || (b3 == -1) || (b4 == -1)) {
0851: throw new Base64DecodingException("decoding.general");//if found "no data" just return null
0852: }
0853:
0854: decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
0855: decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
0856: decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
0857: }
0858: return decodedData;
0859: }
0860:
0861: /**
0862: * Decodes Base64 data into outputstream
0863: *
0864: * @param base64Data Byte array containing Base64 data
0865: * @param os the outputstream
0866: * @throws IOException
0867: * @throws Base64DecodingException
0868: */
0869: public final static void decode(byte[] base64Data, OutputStream os)
0870: throws Base64DecodingException, IOException {
0871: // remove white spaces
0872: int len = removeWhiteSpace(base64Data);
0873:
0874: if (len % FOURBYTE != 0) {
0875: throw new Base64DecodingException("decoding.divisible.four");
0876: //should be divisible by four
0877: }
0878:
0879: int numberQuadruple = (len / FOURBYTE);
0880:
0881: if (numberQuadruple == 0)
0882: return;
0883:
0884: //byte decodedData[] = null;
0885: byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
0886:
0887: int i = 0;
0888:
0889: int dataIndex = 0;
0890:
0891: //the begin
0892: for (i = numberQuadruple - 1; i > 0; i--) {
0893: b1 = base64Alphabet[base64Data[dataIndex++]];
0894: b2 = base64Alphabet[base64Data[dataIndex++]];
0895: b3 = base64Alphabet[base64Data[dataIndex++]];
0896: b4 = base64Alphabet[base64Data[dataIndex++]];
0897: if ((b1 == -1) || (b2 == -1) || (b3 == -1) || (b4 == -1))
0898: throw new Base64DecodingException("decoding.general");//if found "no data" just return null
0899:
0900: os.write((byte) (b1 << 2 | b2 >> 4));
0901: os.write((byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)));
0902: os.write((byte) (b3 << 6 | b4));
0903: }
0904: b1 = base64Alphabet[base64Data[dataIndex++]];
0905: b2 = base64Alphabet[base64Data[dataIndex++]];
0906:
0907: // first last bits.
0908: if ((b1 == -1) || (b2 == -1)) {
0909: throw new Base64DecodingException("decoding.general");//if found "no data" just return null
0910: }
0911:
0912: byte d3, d4;
0913: b3 = base64Alphabet[d3 = base64Data[dataIndex++]];
0914: b4 = base64Alphabet[d4 = base64Data[dataIndex++]];
0915: if ((b3 == -1) || (b4 == -1)) {//Check if they are PAD characters
0916: if (isPad(d3) && isPad(d4)) { //Two PAD e.g. 3c[Pad][Pad]
0917: if ((b2 & 0xf) != 0)//last 4 bits should be zero
0918: throw new Base64DecodingException(
0919: "decoding.general");
0920: os.write((byte) (b1 << 2 | b2 >> 4));
0921: } else if (!isPad(d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
0922: if ((b3 & 0x3) != 0)//last 2 bits should be zero
0923: throw new Base64DecodingException(
0924: "decoding.general");
0925: os.write((byte) (b1 << 2 | b2 >> 4));
0926: os
0927: .write((byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)));
0928: } else {
0929: throw new Base64DecodingException("decoding.general");//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
0930: }
0931: } else {
0932: //No PAD e.g 3cQl
0933: os.write((byte) (b1 << 2 | b2 >> 4));
0934: os.write((byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)));
0935: os.write((byte) (b3 << 6 | b4));
0936: }
0937: return;
0938: }
0939:
0940: /**
0941: * Decodes Base64 data into outputstream
0942: *
0943: * @param is containing Base64 data
0944: * @param os the outputstream
0945: * @throws IOException
0946: * @throws Base64DecodingException
0947: */
0948: public final static void decode(InputStream is, OutputStream os)
0949: throws Base64DecodingException, IOException {
0950: //byte decodedData[] = null;
0951: byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
0952:
0953: int index = 0;
0954: byte[] data = new byte[4];
0955: int read;
0956: //the begin
0957: while ((read = is.read()) > 0) {
0958: byte readed = (byte) read;
0959: if (isWhiteSpace(readed)) {
0960: continue;
0961: }
0962: if (isPad(readed)) {
0963: data[index++] = readed;
0964: if (index == 3)
0965: data[index++] = (byte) is.read();
0966: break;
0967: }
0968:
0969: if ((data[index++] = readed) == -1) {
0970: throw new Base64DecodingException("decoding.general");//if found "no data" just return null
0971: }
0972:
0973: if (index != 4) {
0974: continue;
0975: }
0976: index = 0;
0977: b1 = base64Alphabet[data[0]];
0978: b2 = base64Alphabet[data[1]];
0979: b3 = base64Alphabet[data[2]];
0980: b4 = base64Alphabet[data[3]];
0981:
0982: os.write((byte) (b1 << 2 | b2 >> 4));
0983: os.write((byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)));
0984: os.write((byte) (b3 << 6 | b4));
0985: }
0986:
0987: byte d1 = data[0], d2 = data[1], d3 = data[2], d4 = data[3];
0988: b1 = base64Alphabet[d1];
0989: b2 = base64Alphabet[d2];
0990: b3 = base64Alphabet[d3];
0991: b4 = base64Alphabet[d4];
0992: if ((b3 == -1) || (b4 == -1)) {//Check if they are PAD characters
0993: if (isPad(d3) && isPad(d4)) { //Two PAD e.g. 3c[Pad][Pad]
0994: if ((b2 & 0xf) != 0)//last 4 bits should be zero
0995: throw new Base64DecodingException(
0996: "decoding.general");
0997: os.write((byte) (b1 << 2 | b2 >> 4));
0998: } else if (!isPad(d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
0999: b3 = base64Alphabet[d3];
1000: if ((b3 & 0x3) != 0)//last 2 bits should be zero
1001: throw new Base64DecodingException(
1002: "decoding.general");
1003: os.write((byte) (b1 << 2 | b2 >> 4));
1004: os
1005: .write((byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)));
1006: } else {
1007: throw new Base64DecodingException("decoding.general");//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
1008: }
1009: } else {
1010: //No PAD e.g 3cQl
1011:
1012: os.write((byte) (b1 << 2 | b2 >> 4));
1013: os.write((byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)));
1014: os.write((byte) (b3 << 6 | b4));
1015: }
1016:
1017: return;
1018: }
1019:
1020: /**
1021: * remove WhiteSpace from MIME containing encoded Base64 data.
1022: *
1023: * @param data the byte array of base64 data (with WS)
1024: * @return the new length
1025: */
1026: protected static int removeWhiteSpace(byte[] data) {
1027: if (data == null)
1028: return 0;
1029:
1030: // count characters that's not whitespace
1031: int newSize = 0;
1032: int len = data.length;
1033: for (int i = 0; i < len; i++) {
1034: byte dataS = data[i];
1035: if (!isWhiteSpace(dataS))
1036: data[newSize++] = dataS;
1037: }
1038: return newSize;
1039: }
1040: }
|