/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */
package com.sun.org.apache.xml.internal.security.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.Text;
Implementation of MIME's Base64 encoding and decoding conversions. Optimized code. (raw version taken from oreilly.jonathan.util, and currently org.apache.xerces.ds.util.Base64)
Author:Raul Benito(Of the xerces copy, and little adaptations)., Anli Shundi, Christian Geuer-Pollmann
See Also:
/** * Implementation of MIME's Base64 encoding and decoding conversions. * Optimized code. (raw version taken from oreilly.jonathan.util, * and currently org.apache.xerces.ds.util.Base64) * * @author Raul Benito(Of the xerces copy, and little adaptations). * @author Anli Shundi * @author Christian Geuer-Pollmann * @see <A HREF="ftp://ftp.isi.edu/in-notes/rfc2045.txt">RFC 2045</A> * @see com.sun.org.apache.xml.internal.security.transforms.implementations.TransformBase64Decode */
public class Base64 {
Field BASE64DEFAULTLENGTH
/** Field BASE64DEFAULTLENGTH */
public static final int BASE64DEFAULTLENGTH = 76; private static final int BASELENGTH = 255; private static final int LOOKUPLENGTH = 64; private static final int TWENTYFOURBITGROUP = 24; private static final int EIGHTBIT = 8; private static final int SIXTEENBIT = 16; private static final int FOURBYTE = 4; private static final int SIGN = -128; private static final char PAD = '='; private static final byte [] base64Alphabet = new byte[BASELENGTH]; private static final char [] lookUpBase64Alphabet = new char[LOOKUPLENGTH]; static { for (int i = 0; i < BASELENGTH; i++) { base64Alphabet[i] = -1; } for (int i = 'Z'; i >= 'A'; i--) { base64Alphabet[i] = (byte) (i - 'A'); } for (int i = 'z'; i>= 'a'; i--) { base64Alphabet[i] = (byte) (i - 'a' + 26); } for (int i = '9'; i >= '0'; i--) { base64Alphabet[i] = (byte) (i - '0' + 52); } base64Alphabet['+'] = 62; base64Alphabet['/'] = 63; for (int i = 0; i <= 25; i++) { lookUpBase64Alphabet[i] = (char)('A' + i); } for (int i = 26, j = 0; i <= 51; i++, j++) { lookUpBase64Alphabet[i] = (char)('a' + j); } for (int i = 52, j = 0; i <= 61; i++, j++) { lookUpBase64Alphabet[i] = (char)('0' + j); } lookUpBase64Alphabet[62] = '+'; lookUpBase64Alphabet[63] = '/'; } private Base64() { // we don't allow instantiation }
Returns a byte-array representation of a BigInteger. No sign-bit is output. N.B.: BigInteger's toByteArray returns eventually longer arrays because of the leading sign-bit.
Params:
  • big – BigInteger to be converted
  • bitlen – int the desired length in bits of the representation
Returns:a byte array with bitlen bits of big
/** * Returns a byte-array representation of a <code>{@link BigInteger}<code>. * No sign-bit is output. * * <b>N.B.:</B> <code>{@link BigInteger}<code>'s toByteArray * returns eventually longer arrays because of the leading sign-bit. * * @param big <code>BigInteger<code> to be converted * @param bitlen <code>int<code> the desired length in bits of the representation * @return a byte array with <code>bitlen</code> bits of <code>big</code> */
static final byte[] getBytes(BigInteger big, int bitlen) { //round bitlen bitlen = ((bitlen + 7) >> 3) << 3; if (bitlen < big.bitLength()) { throw new IllegalArgumentException(I18n.translate("utils.Base64.IllegalBitlength")); } byte[] bigBytes = big.toByteArray(); if (((big.bitLength() % 8) != 0) && (((big.bitLength() / 8) + 1) == (bitlen / 8))) { return bigBytes; } // some copying needed int startSrc = 0; // no need to skip anything int bigLen = bigBytes.length; //valid length of the string if ((big.bitLength() % 8) == 0) { // correct values startSrc = 1; // skip sign bit bigLen--; // valid length of the string } int startDst = bitlen / 8 - bigLen; //pad with leading nulls byte[] resizedBytes = new byte[bitlen / 8]; System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, bigLen); return resizedBytes; }
Encode in Base64 the given BigInteger.
Params:
  • big –
Returns:String with Base64 encoding
/** * Encode in Base64 the given <code>{@link BigInteger}<code>. * * @param big * @return String with Base64 encoding */
public static final String encode(BigInteger big) { return encode(getBytes(big, big.bitLength())); }
Returns a byte-array representation of a BigInteger. No sign-bit is output. N.B.: BigInteger's toByteArray returns eventually longer arrays because of the leading sign-bit.
Params:
  • big – BigInteger to be converted
  • bitlen – int the desired length in bits of the representation
Returns:a byte array with bitlen bits of big
/** * Returns a byte-array representation of a <code>{@link BigInteger}<code>. * No sign-bit is output. * * <b>N.B.:</B> <code>{@link BigInteger}<code>'s toByteArray * returns eventually longer arrays because of the leading sign-bit. * * @param big <code>BigInteger<code> to be converted * @param bitlen <code>int<code> the desired length in bits of the representation * @return a byte array with <code>bitlen</code> bits of <code>big</code> */
public static final byte[] encode(BigInteger big, int bitlen) { //round bitlen bitlen = ((bitlen + 7) >> 3) << 3; if (bitlen < big.bitLength()) { throw new IllegalArgumentException(I18n.translate("utils.Base64.IllegalBitlength")); } byte[] bigBytes = big.toByteArray(); if (((big.bitLength() % 8) != 0) && (((big.bitLength() / 8) + 1) == (bitlen / 8))) { return bigBytes; } // some copying needed int startSrc = 0; // no need to skip anything int bigLen = bigBytes.length; //valid length of the string if ((big.bitLength() % 8) == 0) { // correct values startSrc = 1; // skip sign bit bigLen--; // valid length of the string } int startDst = bitlen / 8 - bigLen; //pad with leading nulls byte[] resizedBytes = new byte[bitlen / 8]; System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, bigLen); return resizedBytes; }
Method decodeBigIntegerFromElement
Params:
  • element –
Throws:
Returns:the biginteger obtained from the node
/** * Method decodeBigIntegerFromElement * * @param element * @return the biginteger obtained from the node * @throws Base64DecodingException */
public static final BigInteger decodeBigIntegerFromElement(Element element) throws Base64DecodingException { return new BigInteger(1, Base64.decode(element)); }
Method decodeBigIntegerFromText
Params:
  • text –
Throws:
Returns:the biginter obtained from the text node
/** * Method decodeBigIntegerFromText * * @param text * @return the biginter obtained from the text node * @throws Base64DecodingException */
public static final BigInteger decodeBigIntegerFromText(Text text) throws Base64DecodingException { return new BigInteger(1, Base64.decode(text.getData())); }
This method takes an (empty) Element and a BigInteger and adds the base64 encoded BigInteger to the Element.
Params:
  • element –
  • biginteger –
/** * This method takes an (empty) Element and a BigInteger and adds the * base64 encoded BigInteger to the Element. * * @param element * @param biginteger */
public static final void fillElementWithBigInteger(Element element, BigInteger biginteger) { String encodedInt = encode(biginteger); if (!XMLUtils.ignoreLineBreaks() && encodedInt.length() > BASE64DEFAULTLENGTH) { encodedInt = "\n" + encodedInt + "\n"; } Document doc = element.getOwnerDocument(); Text text = doc.createTextNode(encodedInt); element.appendChild(text); }
Method decode Takes the Text children of the Element and interprets them as input for the Base64.decode() function.
Params:
  • element –
Throws:
Returns:the byte obtained of the decoding the element $todo$ not tested yet
/** * Method decode * * Takes the <CODE>Text</CODE> children of the Element and interprets * them as input for the <CODE>Base64.decode()</CODE> function. * * @param element * @return the byte obtained of the decoding the element * $todo$ not tested yet * @throws Base64DecodingException */
public static final byte[] decode(Element element) throws Base64DecodingException { Node sibling = element.getFirstChild(); StringBuilder sb = new StringBuilder(); while (sibling != null) { if (sibling.getNodeType() == Node.TEXT_NODE) { Text t = (Text) sibling; sb.append(t.getData()); } sibling = sibling.getNextSibling(); } return decode(sb.toString()); }
Method encodeToElement
Params:
  • doc –
  • localName –
  • bytes –
Returns:an Element with the base64 encoded in the text.
/** * Method encodeToElement * * @param doc * @param localName * @param bytes * @return an Element with the base64 encoded in the text. * */
public static final Element encodeToElement(Document doc, String localName, byte[] bytes) { Element el = XMLUtils.createElementInSignatureSpace(doc, localName); Text text = doc.createTextNode(encode(bytes)); el.appendChild(text); return el; }
Method decode
Params:
  • base64 –
Throws:
Returns:the UTF bytes of the base64
/** * Method decode * * @param base64 * @return the UTF bytes of the base64 * @throws Base64DecodingException * */
public static final byte[] decode(byte[] base64) throws Base64DecodingException { return decodeInternal(base64, -1); }
Encode a byte array and fold lines at the standard 76th character unless ignore line breaks property is set.
Params:
  • binaryData – byte[] to be base64 encoded
Returns:the String with encoded data
/** * Encode a byte array and fold lines at the standard 76th character unless * ignore line breaks property is set. * * @param binaryData <code>byte[]<code> to be base64 encoded * @return the <code>String<code> with encoded data */
public static final String encode(byte[] binaryData) { return XMLUtils.ignoreLineBreaks() ? encode(binaryData, Integer.MAX_VALUE) : encode(binaryData, BASE64DEFAULTLENGTH); }
Base64 decode the lines from the reader and return an InputStream with the bytes.
Params:
  • reader –
Throws:
Returns:InputStream with the decoded bytes
/** * Base64 decode the lines from the reader and return an InputStream * with the bytes. * * @param reader * @return InputStream with the decoded bytes * @exception IOException passes what the reader throws * @throws IOException * @throws Base64DecodingException */
public static final byte[] decode(BufferedReader reader) throws IOException, Base64DecodingException { byte[] retBytes = null; UnsyncByteArrayOutputStream baos = null; try { baos = new UnsyncByteArrayOutputStream(); String line; while (null != (line = reader.readLine())) { byte[] bytes = decode(line); baos.write(bytes); } retBytes = baos.toByteArray(); } finally { baos.close(); } return retBytes; } protected static final boolean isWhiteSpace(byte octect) { return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9); } protected static final boolean isPad(byte octect) { return (octect == PAD); } /** * Encodes hex octets into Base64 * * @param binaryData Array containing binaryData * @return Encoded Base64 array */
Encode a byte array in Base64 format and return an optionally wrapped line.
Params:
  • binaryData – byte[] data to be encoded
  • length – int length of wrapped lines; No wrapping if less than 4.
Returns:a String with encoded data
/** * Encode a byte array in Base64 format and return an optionally * wrapped line. * * @param binaryData <code>byte[]</code> data to be encoded * @param length <code>int<code> length of wrapped lines; No wrapping if less than 4. * @return a <code>String</code> with encoded data */
public static final String encode(byte[] binaryData,int length) { if (length < 4) { length = Integer.MAX_VALUE; } if (binaryData == null) { return null; } long lengthDataBits = ((long) binaryData.length) * ((long) EIGHTBIT); if (lengthDataBits == 0L) { return ""; } long fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP; int numberTriplets = (int) (lengthDataBits / TWENTYFOURBITGROUP); int numberQuartet = fewerThan24bits != 0L ? numberTriplets + 1 : numberTriplets; int quartesPerLine = length / 4; int numberLines = (numberQuartet - 1) / quartesPerLine; char encodedData[] = null; encodedData = new char[numberQuartet * 4 + numberLines]; byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; int encodedIndex = 0; int dataIndex = 0; int i = 0; for (int line = 0; line < numberLines; line++) { for (int quartet = 0; quartet < 19; quartet++) { b1 = binaryData[dataIndex++]; b2 = binaryData[dataIndex++]; b3 = binaryData[dataIndex++]; l = (byte)(b2 & 0x0f); k = (byte)(b1 & 0x03); byte val1 = ((b1 & SIGN) == 0) ? (byte)(b1 >> 2): (byte)((b1) >> 2 ^ 0xc0); byte val2 = ((b2 & SIGN) == 0) ? (byte)(b2 >> 4) : (byte)((b2) >> 4 ^ 0xf0); byte val3 = ((b3 & SIGN) == 0) ? (byte)(b3 >> 6) : (byte)((b3) >> 6 ^ 0xfc); encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; i++; } encodedData[encodedIndex++] = 0xa; } for (; i < numberTriplets; i++) { b1 = binaryData[dataIndex++]; b2 = binaryData[dataIndex++]; b3 = binaryData[dataIndex++]; l = (byte)(b2 & 0x0f); k = (byte)(b1 & 0x03); byte val1 = ((b1 & SIGN) == 0) ? (byte)(b1 >> 2) : (byte)((b1) >> 2 ^ 0xc0); byte val2 = ((b2 & SIGN) == 0) ? (byte)(b2 >> 4) : (byte)((b2) >> 4 ^ 0xf0); byte val3 = ((b3 & SIGN) == 0) ? (byte)(b3 >> 6) : (byte)((b3) >> 6 ^ 0xfc); encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3]; encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f]; } // form integral number of 6-bit groups if (fewerThan24bits == EIGHTBIT) { b1 = binaryData[dataIndex]; k = (byte) (b1 &0x03); byte val1 = ((b1 & SIGN) == 0) ? (byte)(b1 >> 2):(byte)((b1) >> 2 ^ 0xc0); encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4]; encodedData[encodedIndex++] = PAD; encodedData[encodedIndex++] = PAD; } else if (fewerThan24bits == SIXTEENBIT) { b1 = binaryData[dataIndex]; b2 = binaryData[dataIndex +1 ]; l = ( byte ) (b2 & 0x0f); k = ( byte ) (b1 & 0x03); byte val1 = ((b1 & SIGN) == 0) ? (byte)(b1 >> 2) : (byte)((b1) >> 2 ^ 0xc0); byte val2 = ((b2 & SIGN) == 0) ? (byte)(b2 >> 4) : (byte)((b2) >> 4 ^ 0xf0); encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)]; encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; encodedData[encodedIndex++] = PAD; } //encodedData[encodedIndex] = 0xa; return new String(encodedData); }
Decodes Base64 data into octets
Params:
  • encoded – String containing base64 encoded data
Throws:
Returns:byte array containing the decoded data
/** * Decodes Base64 data into octets * * @param encoded String containing base64 encoded data * @return byte array containing the decoded data * @throws Base64DecodingException if there is a problem decoding the data */
public static final byte[] decode(String encoded) throws Base64DecodingException { if (encoded == null) { return null; } byte[] bytes = new byte[encoded.length()]; int len = getBytesInternal(encoded, bytes); return decodeInternal(bytes, len); } protected static final int getBytesInternal(String s, byte[] result) { int length = s.length(); int newSize = 0; for (int i = 0; i < length; i++) { byte dataS = (byte)s.charAt(i); if (!isWhiteSpace(dataS)) { result[newSize++] = dataS; } } return newSize; } protected static final byte[] decodeInternal(byte[] base64Data, int len) throws Base64DecodingException { // remove white spaces if (len == -1) { len = removeWhiteSpace(base64Data); } if (len % FOURBYTE != 0) { throw new Base64DecodingException("decoding.divisible.four"); //should be divisible by four } int numberQuadruple = (len / FOURBYTE); if (numberQuadruple == 0) { return new byte[0]; } byte decodedData[] = null; byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; int i = 0; int encodedIndex = 0; int dataIndex = 0; //decodedData = new byte[ (numberQuadruple)*3]; dataIndex = (numberQuadruple - 1) * 4; encodedIndex = (numberQuadruple - 1) * 3; //first last bits. b1 = base64Alphabet[base64Data[dataIndex++]]; b2 = base64Alphabet[base64Data[dataIndex++]]; if ((b1==-1) || (b2==-1)) { //if found "no data" just return null throw new Base64DecodingException("decoding.general"); } byte d3, d4; b3 = base64Alphabet[d3 = base64Data[dataIndex++]]; b4 = base64Alphabet[d4 = base64Data[dataIndex++]]; if ((b3 == -1) || (b4 == -1) ) { //Check if they are PAD characters if (isPad(d3) && isPad(d4)) { //Two PAD e.g. 3c[Pad][Pad] if ((b2 & 0xf) != 0) { //last 4 bits should be zero throw new Base64DecodingException("decoding.general"); } decodedData = new byte[encodedIndex + 1]; decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4) ; } else if (!isPad(d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad] if ((b3 & 0x3) != 0) { //last 2 bits should be zero throw new Base64DecodingException("decoding.general"); } decodedData = new byte[encodedIndex + 2]; decodedData[encodedIndex++] = (byte)(b1 << 2 | b2 >> 4); decodedData[encodedIndex] = (byte)(((b2 & 0xf) << 4) |((b3 >> 2) & 0xf)); } else { //an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data throw new Base64DecodingException("decoding.general"); } } else { //No PAD e.g 3cQl decodedData = new byte[encodedIndex+3]; decodedData[encodedIndex++] = (byte)(b1 << 2 | b2 >> 4) ; decodedData[encodedIndex++] = (byte)(((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); decodedData[encodedIndex++] = (byte)(b3 << 6 | b4); } encodedIndex = 0; dataIndex = 0; //the begin for (i = numberQuadruple - 1; i > 0; i--) { b1 = base64Alphabet[base64Data[dataIndex++]]; b2 = base64Alphabet[base64Data[dataIndex++]]; b3 = base64Alphabet[base64Data[dataIndex++]]; b4 = base64Alphabet[base64Data[dataIndex++]]; if ((b1 == -1) || (b2 == -1) || (b3 == -1) || (b4 == -1)) { //if found "no data" just return null throw new Base64DecodingException("decoding.general"); } decodedData[encodedIndex++] = (byte)(b1 << 2 | b2 >> 4) ; decodedData[encodedIndex++] = (byte)(((b2 & 0xf) << 4) |((b3 >> 2) & 0xf)); decodedData[encodedIndex++] = (byte)(b3 << 6 | b4 ); } return decodedData; }
Decodes Base64 data into outputstream
Params:
  • base64Data – String containing Base64 data
  • os – the outputstream
Throws:
/** * Decodes Base64 data into outputstream * * @param base64Data String containing Base64 data * @param os the outputstream * @throws IOException * @throws Base64DecodingException */
public static final void decode(String base64Data, OutputStream os) throws Base64DecodingException, IOException { byte[] bytes = new byte[base64Data.length()]; int len = getBytesInternal(base64Data, bytes); decode(bytes,os,len); }
Decodes Base64 data into outputstream
Params:
  • base64Data – Byte array containing Base64 data
  • os – the outputstream
Throws:
/** * Decodes Base64 data into outputstream * * @param base64Data Byte array containing Base64 data * @param os the outputstream * @throws IOException * @throws Base64DecodingException */
public static final void decode(byte[] base64Data, OutputStream os) throws Base64DecodingException, IOException { decode(base64Data,os,-1); } protected static final void decode(byte[] base64Data, OutputStream os, int len) throws Base64DecodingException, IOException { // remove white spaces if (len == -1) { len = removeWhiteSpace(base64Data); } if (len % FOURBYTE != 0) { throw new Base64DecodingException("decoding.divisible.four"); //should be divisible by four } int numberQuadruple = (len / FOURBYTE); if (numberQuadruple == 0) { return; } //byte decodedData[] = null; byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; int i = 0; int dataIndex = 0; //the begin for (i=numberQuadruple - 1; i > 0; i--) { b1 = base64Alphabet[base64Data[dataIndex++]]; b2 = base64Alphabet[base64Data[dataIndex++]]; b3 = base64Alphabet[base64Data[dataIndex++]]; b4 = base64Alphabet[base64Data[dataIndex++]]; if ((b1 == -1) || (b2 == -1) || (b3 == -1) || (b4 == -1) ) { //if found "no data" just return null throw new Base64DecodingException("decoding.general"); } os.write((byte)(b1 << 2 | b2 >> 4)); os.write((byte)(((b2 & 0xf) << 4 ) | ((b3 >> 2) & 0xf))); os.write( (byte)(b3 << 6 | b4)); } b1 = base64Alphabet[base64Data[dataIndex++]]; b2 = base64Alphabet[base64Data[dataIndex++]]; // first last bits. if ((b1 == -1) || (b2 == -1) ) { //if found "no data" just return null throw new Base64DecodingException("decoding.general"); } byte d3, d4; b3 = base64Alphabet[d3 = base64Data[dataIndex++]]; b4 = base64Alphabet[d4 = base64Data[dataIndex++]]; if ((b3 == -1 ) || (b4 == -1) ) { //Check if they are PAD characters if (isPad(d3) && isPad(d4)) { //Two PAD e.g. 3c[Pad][Pad] if ((b2 & 0xf) != 0) { //last 4 bits should be zero throw new Base64DecodingException("decoding.general"); } os.write((byte)(b1 << 2 | b2 >> 4)); } else if (!isPad(d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad] if ((b3 & 0x3 ) != 0) { //last 2 bits should be zero throw new Base64DecodingException("decoding.general"); } os.write((byte)(b1 << 2 | b2 >> 4)); os.write((byte)(((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf))); } else { //an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data throw new Base64DecodingException("decoding.general"); } } else { //No PAD e.g 3cQl os.write((byte)(b1 << 2 | b2 >> 4)); os.write( (byte)(((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf))); os.write((byte)(b3 << 6 | b4)); } }
Decodes Base64 data into outputstream
Params:
  • is – containing Base64 data
  • os – the outputstream
Throws:
/** * Decodes Base64 data into outputstream * * @param is containing Base64 data * @param os the outputstream * @throws IOException * @throws Base64DecodingException */
public static final void decode(InputStream is, OutputStream os) throws Base64DecodingException, IOException { //byte decodedData[] = null; byte b1 = 0, b2 = 0, b3 = 0, b4 = 0; int index=0; byte[] data = new byte[4]; int read; //the begin while ((read = is.read()) > 0) { byte readed = (byte)read; if (isWhiteSpace(readed)) { continue; } if (isPad(readed)) { data[index++] = readed; if (index == 3) { data[index++] = (byte)is.read(); } break; } if ((data[index++] = readed) == -1) { //if found "no data" just return null throw new Base64DecodingException("decoding.general"); } if (index != 4) { continue; } index = 0; b1 = base64Alphabet[data[0]]; b2 = base64Alphabet[data[1]]; b3 = base64Alphabet[data[2]]; b4 = base64Alphabet[data[3]]; os.write((byte)(b1 << 2 | b2 >> 4)); os.write((byte)(((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf))); os.write((byte)(b3 << 6 | b4)); } byte d1 = data[0], d2 = data[1], d3 = data[2], d4 = data[3]; b1 = base64Alphabet[d1]; b2 = base64Alphabet[d2]; b3 = base64Alphabet[d3]; b4 = base64Alphabet[d4]; if ((b3 == -1) || (b4 == -1)) { //Check if they are PAD characters if (isPad(d3) && isPad(d4)) { //Two PAD e.g. 3c[Pad][Pad] if ((b2 & 0xf) != 0) { //last 4 bits should be zero throw new Base64DecodingException("decoding.general"); } os.write((byte)(b1 << 2 | b2 >> 4)); } else if (!isPad(d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad] b3 = base64Alphabet[d3]; if ((b3 & 0x3) != 0) { //last 2 bits should be zero throw new Base64DecodingException("decoding.general"); } os.write((byte)(b1 << 2 | b2 >> 4)); os.write((byte)(((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf))); } else { //an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data throw new Base64DecodingException("decoding.general"); } } else { //No PAD e.g 3cQl os.write((byte)(b1 << 2 | b2 >> 4)); os.write((byte)(((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf))); os.write((byte)(b3 << 6 | b4)); } }
remove WhiteSpace from MIME containing encoded Base64 data.
Params:
  • data – the byte array of base64 data (with WS)
Returns: the new length
/** * remove WhiteSpace from MIME containing encoded Base64 data. * * @param data the byte array of base64 data (with WS) * @return the new length */
protected static final int removeWhiteSpace(byte[] data) { if (data == null) { return 0; } // count characters that's not whitespace int newSize = 0; int len = data.length; for (int i = 0; i < len; i++) { byte dataS = data[i]; if (!isWhiteSpace(dataS)) { data[newSize++] = dataS; } } return newSize; } }