Mega Code Archive

 
Categories / Java / File Input Output
 

Base64 provides Base64 encodingdecoding of strings and streams

/*  * 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.  */ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; /**  * <code>Base64</code> provides Base64 encoding/decoding of strings and streams.  */ public class Base64 {     // charset used for base64 encoded data (7-bit ASCII)     private static final String CHARSET = "US-ASCII";     // encoding table (the 64 valid base64 characters)     private static final char[] BASE64CHARS =             "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();     // decoding table (used to lookup original 6-bit with base64 character     // as table index)     private static final byte[] DECODETABLE = new byte[128];     static {         // initialize decoding table         for (int i = 0; i < DECODETABLE.length; i++) {             DECODETABLE[i] = 0x7f;         }         // build decoding table         for (int i = 0; i < BASE64CHARS.length; i++) {             DECODETABLE[BASE64CHARS[i]] = (byte) i;         }     }     // pad character     private static final char BASE64PAD = '=';     /**      * empty private constructor      */     private Base64() {     }     /**      * Calculates the size (i.e. number of bytes) of the base64 encoded output      * given the length (i.e. number of bytes) of the data to be encoded.      *      * @param dataLength length (i.e. number of bytes) of the data to be encoded      * @return size (i.e. number of bytes) of the base64 encoded output      */     public static long calcEncodedLength(long dataLength) {         long encLen = dataLength * 4 / 3;         encLen += (encLen + 4) % 4;         return encLen;     }     /**      * Pessimistically guesses the size (i.e. number of bytes) of the decoded      * output given the length (i.e. number of bytes) of the base64 encoded      * data.      *      * @param encLength length (i.e. number of bytes) of the base64 encoded data      * @return size (i.e. number of bytes) of the decoded output      */     public static long guessDecodedLength(long encLength) {         long decLen = encLength * 3 / 4;         return decLen + 3;     }     /**      * Outputs base64 representation of the specified stream data to a      * <code>Writer</code>.      *      * @param in     stream data to be encoded      * @param writer writer to output the encoded data      * @throws java.io.IOException if an i/o error occurs      */     public static void encode(InputStream in, Writer writer)             throws IOException {         // encode stream data in chunks;         // chunksize must be a multiple of 3 in order         // to avoid padding within output         byte[] buffer = new byte[9 * 1024];         int read;         while ((read = in.read(buffer)) > 0) {             encode(buffer, 0, read, writer);         }     }     /**      * Outputs base64 representation of the specified stream data to an      * <code>OutputStream</code>.      *      * @param in  stream data to be encoded      * @param out stream where the encoded data should be written to      * @throws java.io.IOException if an i/o error occurs      */     public static void encode(InputStream in, OutputStream out)             throws IOException {         Writer writer = new OutputStreamWriter(out, CHARSET);         encode(in, writer);     }     /**      * Outputs base64 representation of the specified data to a      * <code>Writer</code>.      *      * @param data   data to be encoded      * @param off    offset within data at which to start encoding      * @param len    length of data to encode      * @param writer writer to output the encoded data      * @throws java.io.IOException if an i/o error occurs      */     public static void encode(byte[] data, int off, int len, Writer writer)             throws IOException {         if (len == 0) {             return;         }         if (len < 0 || off >= data.length                 || len + off > data.length) {             throw new IllegalArgumentException();         }         char[] enc = new char[4];         while (len >= 3) {             int i = ((data[off] & 0xff) << 16)                     + ((data[off + 1] & 0xff) << 8)                     + (data[off + 2] & 0xff);             enc[0] = BASE64CHARS[i >> 18];             enc[1] = BASE64CHARS[(i >> 12) & 0x3f];             enc[2] = BASE64CHARS[(i >> 6) & 0x3f];             enc[3] = BASE64CHARS[i & 0x3f];             writer.write(enc, 0, 4);             off += 3;             len -= 3;         }         // add padding if necessary         if (len == 1) {             int i = data[off] & 0xff;             enc[0] = BASE64CHARS[i >> 2];             enc[1] = BASE64CHARS[(i << 4) & 0x3f];             enc[2] = BASE64PAD;             enc[3] = BASE64PAD;             writer.write(enc, 0, 4);         } else if (len == 2) {             int i = ((data[off] & 0xff) << 8) + (data[off + 1] & 0xff);             enc[0] = BASE64CHARS[i >> 10];             enc[1] = BASE64CHARS[(i >> 4) & 0x3f];             enc[2] = BASE64CHARS[(i << 2) & 0x3f];             enc[3] = BASE64PAD;             writer.write(enc, 0, 4);         }     }     /**      * Decode base64 encoded data.      *      * @param reader reader for the base64 encoded data to be decoded      * @param out    stream where the decoded data should be written to      * @throws java.io.IOException if an i/o error occurs      */     public static void decode(Reader reader, OutputStream out)             throws IOException {         char[] chunk = new char[8192];         int read;         while ((read = reader.read(chunk)) > -1) {             decode(chunk, 0, read, out);         }     }     /**      * Decode base64 encoded data. The data read from the inputstream is      * assumed to be of charset "US-ASCII".      *      * @param in  inputstream of the base64 encoded data to be decoded      * @param out stream where the decoded data should be written to      * @throws java.io.IOException if an i/o error occurs      */     public static void decode(InputStream in, OutputStream out)             throws IOException {         decode(new InputStreamReader(in, CHARSET), out);     }     /**      * Decode base64 encoded data.      *      * @param data the base64 encoded data to be decoded      * @param out  stream where the decoded data should be written to      * @throws java.io.IOException if an i/o error occurs      */     public static void decode(String data, OutputStream out)             throws IOException {         char[] chars = data.toCharArray();         decode(chars, 0, chars.length, out);     }     /**      * Decode base64 encoded data.      *      * @param chars the base64 encoded data to be decoded      * @param out   stream where the decoded data should be written to      * @throws java.io.IOException if an i/o error occurs      */     public static void decode(char[] chars, OutputStream out)             throws IOException {         decode(chars, 0, chars.length, out);     }     /**      * Decode base64 encoded data.      *      * @param chars the base64 encoded data to be decoded      * @param off   offset within data at which to start decoding      * @param len   length of data to decode      * @param out   stream where the decoded data should be written to      * @throws java.io.IOException if an i/o error occurs      */     public static void decode(char[] chars, int off, int len, OutputStream out)             throws IOException {         if (len == 0) {             return;         }         if (len < 0 || off >= chars.length                 || len + off > chars.length) {             throw new IllegalArgumentException();         }         char[] chunk = new char[4];         byte[] dec = new byte[3];         int posChunk = 0;         // decode in chunks of 4 characters         for (int i = off; i < (off + len); i++) {             char c = chars[i];             if (c < DECODETABLE.length && DECODETABLE[c] != 0x7f                     || c == BASE64PAD) {                 chunk[posChunk++] = c;                 if (posChunk == chunk.length) {                     int b0 = DECODETABLE[chunk[0]];                     int b1 = DECODETABLE[chunk[1]];                     int b2 = DECODETABLE[chunk[2]];                     int b3 = DECODETABLE[chunk[3]];                     if (chunk[3] == BASE64PAD && chunk[2] == BASE64PAD) {                         dec[0] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);                         out.write(dec, 0, 1);                     } else if (chunk[3] == BASE64PAD) {                         dec[0] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);                         dec[1] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);                         out.write(dec, 0, 2);                     } else {                         dec[0] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);                         dec[1] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);                         dec[2] = (byte) (b2 << 6 & 0xc0 | b3 & 0x3f);                         out.write(dec, 0, 3);                     }                     posChunk = 0;                 }             } else {                 throw new IllegalArgumentException("specified data is not base64 encoded");             }         }     } }