Skip to content

Instantly share code, notes, and snippets.

@ochinchina
Created January 5, 2015 05:54
Show Gist options
  • Save ochinchina/a9b3c9d58e75e8bd552b to your computer and use it in GitHub Desktop.
Save ochinchina/a9b3c9d58e75e8bd552b to your computer and use it in GitHub Desktop.
/*
* Copyright (c) 2014 by its authors. Some rights reserved.
*
* Licensed 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.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
* encode/decode a normal/base64 string/array to base64/normal string/array
*
* @author Steven Ou
*
*/
public class Base64 {
private static final char[] indexToChar;
private static final byte[] charToIndex;
static {
indexToChar = new char[]{'A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X',
'Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3',
'4','5','6','7','8','9','+','/'};
charToIndex = new byte[256];
Arrays.fill(charToIndex, (byte)0xff);
for( int i = 0, n = indexToChar.length; i < n; i++ ) {
charToIndex[ indexToChar[i] ] = (byte)i;
}
}
/**
* encode a string to base64 string
*
* @param s the string
* @return the base64 string
*/
public static String encode( String s) {
try {
return new String( encode( s.getBytes("UTF-8")), "UTF-8" );
}catch( Exception ex ) {
}
return "";
}
/**
* same as <code>encode(b,0,b.length)</code>
*
* @param b the byte array
* @return the encoded base64 byte array
*/
public static byte[] encode( byte[] b ) {
return encode( b, 0, b.length );
}
/**
* encode the byte array <code>b</code> with <code>offset</code> and <code>len</code>
*
* @param b
* @param offset
* @param len
* @return
*/
public static byte[] encode( byte[] b, int offset, int len ) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for( ; len > 0 ; ) {
switch( len ) {
case 1:
toBase64( b, offset, 1, bos );
len --;
offset ++;
break;
case 2:
toBase64( b, offset, 2, bos );
len -= 2;
offset += 2;
break;
default:
toBase64( b, offset, 3, bos );
len -= 3;
offset += 3;
break;
}
}
return bos.toByteArray();
}
/**
* decode a base64 array <code>b</code> to normal byte array
* @param b the base64 array
* @return the normal byte array
*/
public static byte[] decode( byte[] b ) {
return decode( b, 0, b.length );
}
/**
* decode a base64 string <code>s</code> to normal string
* @param s the base64 string
* @return the normal string
*/
public static String decode( String s ) {
try {
return new String( decode( s.getBytes("UTF-8")), "UTF-8");
} catch (UnsupportedEncodingException e) {
}
return "";
}
/**
* decode a base64 array to a normal byte array
*
* @param b the base64 array
* @param offset the offset of the base64 array
* @param len the length of the base64 array
* @return the normal byte array
*/
public static byte[] decode( byte[] b, int offset, int len ) {
if( (len & 0x03) != 0 ) {
throw new IllegalArgumentException( "length of encoded base64 must be multiple of 4");
}
if( len <= 0 ) return new byte[0];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for( int n = len - 4 ;n > 0; n -= 4, offset += 4 ) {
base64ToChar( b, offset, 4, bos );
}
if( b[len-1] == '=') {
if( b[len-2] == '=') {
base64ToChar( b, len - 4, 2, bos );
} else {
base64ToChar( b, len - 4, 3, bos );
}
} else {
base64ToChar( b, len - 4, 4, bos );
}
return bos.toByteArray();
}
private static void toBase64(byte[] b, int offset, int n, ByteArrayOutputStream bos) {
int i = 0;
switch( n ) {
case 1:
i = (b[offset] & 0xff) << 16;
bos.write(indexToChar[ (i>>18) & 0x3f ] );
bos.write(indexToChar[ (i>>12) & 0x3f ] );
bos.write( '=');
bos.write( '=');
break;
case 2:
i = ((b[offset] & 0xff) << 16) | ((b[offset+1] & 0xff) << 8);
bos.write(indexToChar[ (i>>18) & 0x3f] );
bos.write(indexToChar[(i>>12) & 0x3f] );
bos.write(indexToChar[(i>>6) & 0x3f] );
bos.write( '=');
break;
case 3:
i = ((b[offset] & 0xff) << 16) | ((b[offset+1] & 0xff) << 8) | (b[offset+2] & 0xff);
bos.write(indexToChar[(i>>18) & 0x3f] );
bos.write(indexToChar[(i>>12) & 0x3f] );
bos.write(indexToChar[(i>>6) & 0x3f] );
bos.write(indexToChar[ i & 0x3f ]);
break;
}
}
private static void base64ToChar(byte[] b, int offset, int n, ByteArrayOutputStream bos) {
int i = base64CharToIndex( b, offset, n );
switch ( n ) {
case 4:
bos.write( i >> 16 );
bos.write( i >> 8 );
bos.write( i );
break;
case 3:
bos.write( i >> 16 );
bos.write( i >> 8 );
break;
case 2:
bos.write( i >> 16 );
break;
}
}
private static int base64CharToIndex( byte[] b, int offset, int n ) {
switch( n ) {
case 4:
return ( base64CharToIndex( b[offset] ) << 18 ) |
( base64CharToIndex( b[offset + 1] ) << 12 ) |
( base64CharToIndex( b[offset + 2] ) << 6 ) |
base64CharToIndex( b[offset + 3] );
case 3:
return ( base64CharToIndex( b[offset] ) << 18 ) |
( base64CharToIndex( b[offset + 1] ) << 12 ) |
( base64CharToIndex( b[offset + 2] ) << 6 );
case 2:
return ( base64CharToIndex( b[offset] ) << 18 ) |
( base64CharToIndex( b[offset+1] ) << 12 );
default:
throw new IllegalArgumentException( "Not a valid base64 encoding");
}
}
private static int base64CharToIndex( int ch ) {
int i = charToIndex[ ch & 0xff ];
if( i == -1 ) throw new IllegalArgumentException( "Not a valid base64 char");
return i & 0x3f;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment