AndroidアプリでBase64を使う必要があったのですが、どうやらAndroidには入っていないようです。
(ドキュメントには存在するんだけどなー Base64 | Android Developers)
ないなら作るか。というわけで、Base64を実装してみました。
先に白状しておくと、非常にわかりにくいコードです。もっと良い実装があるんだろうけど、ギブアップでした。
(一応もう一つ実装したんですが、速度テストしてみると遅かったです)
public class Base64 { private static final String TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; public static String encode(String data){ try{ return encode(data.getBytes("UTF-8")); }catch(Exception e){ return ""; } } public static String encode(byte data[]){ if(data.length == 0){ return ""; } int i; int index[] = new int[1 + data.length * 4 / 3]; int count = 0; int limit = data.length - 3; int mod; int padding; StringBuilder result = new StringBuilder(""); for(i = 0; i < limit; i+=3){ index[count++] = (data[i] & 0xfc) >>> 2; index[count++] = ((data[i] & 0x03) << 4) + ((data[i+1] & 0xf0) >>> 4); index[count++] = ((data[i+1] & 0x0f) << 2) + ((data[i+2] & 0xc0) >>> 6); index[count++] = ((data[i+2]) & 0x3f); } mod = data.length % 3; if(mod == 0){ index[count++] = (data[i] & 0xfc) >>> 2; index[count++] = ((data[i] & 0x03) << 4) + ((data[i+1] & 0xf0) >>> 4); index[count++] = ((data[i+1] & 0x0f) << 2) + ((data[i+2] & 0xc0) >>> 6); index[count++] = ((data[i+2]) & 0x3f); } else if(mod == 1){ index[count++] = (data[i] & 0xfc) >>> 2; index[count++] = (data[i] & 0x03) << 4; } else if(mod == 2){ index[count++] = (data[i] & 0xfc) >>> 2; index[count++] = ((data[i] & 0x03) << 4) + ((data[i+1] & 0xf0) >>> 4); index[count++] = (data[i+1] & 0x0f) << 2; } for(i = 0 ; i < count; i++){ result.append(TABLE.charAt(index[i])); } padding = (4 - result.length() % 4) % 4; for(i = 0 ; i < padding ; i++){ result.append("="); } return result.toString(); } public static String decodeToString(String base64){ return new String(decode(base64)); } public static byte[] decode(String base64){ int i; int length = base64.length(); int data[] = new int[length]; byte result[] = new byte[1 + length * 3 / 4]; int mod; int limit = length - 4; int count = 0; for(i = 0; i < length; i++){ int c = base64.charAt(i); //TABLE.indexOf()は遅い if('A' <= c && c <= 'Z'){ data[i] = c - 'A'; } else if('a' <= c && c <= 'z'){ data[i] = c - 'a' + 26; } else if('0' <= c && c <= '9'){ data[i] = c - '0' + 52; } else if(c == '+'){ data[i] = 62; } else if(c == '/'){ data[i] = 63; } } for(i = 0; i < limit; i+=4){ result[count++] = (byte)( ((data[i] & 0x03f) << 2) + ((data[i+1] & 0x30) >>> 4) ); result[count++] = (byte)( ((data[i+1] & 0x0f) << 4) + ((data[i+2] & 0x3c) >>> 2) ); result[count++] = (byte)( ((data[i+2] & 0x03) << 6) + (data[i+3] & 0x3f) ); } mod = length % 4; if(mod == 0){ result[count++] = (byte)( ((data[i] & 0x03f) << 2) + ((data[i+1] & 0x30) >>> 4) ); result[count++] = (byte)( ((data[i+1] & 0x0f) << 4) + ((data[i+2] & 0x3c) >>> 2) ); result[count++] = (byte)( ((data[i+2] & 0x03) << 6) + (data[i+3] & 0x3f) ); } else if(mod == 2){ result[count++] = (byte)( ((data[i] & 0x03f) << 2) + ((data[i+1] & 0x30) >>> 4) ); } else if(mod == 3){ result[count++] = (byte)( ((data[i] & 0x03f) << 2) + ((data[i+1] & 0x30) >>> 4) ); result[count++] = (byte)( ((data[i+1] & 0x0f) << 4) + ((data[i+2] & 0x3c) >>> 2) ); } return result; } }
エンコード速度テスト
public static void encodeTime(){ String data = "The_quick_brown_fox_jumps_over_the_lazy_dog"; byte[] originalData = data.getBytes(); String enc = ""; long t = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { //sun mail util //enc = new String( com.sun.mail.util.BASE64EncoderStream.encode(originalData) ); //apache commons codec //enc = org.apache.commons.codec.binary.Base64.encodeBase64String(originalData); //自作Base64 enc = Base64.encode(originalData); } long t2 = System.currentTimeMillis(); System.out.println(t2 - t); }
デコード速度テスト
public static void decodeTime(){ String data = "The_quick_brown_fox_jumps_over_the_lazy_dog"; String enc = Base64.encode(data); byte dec[]; long t = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { //sun mail util //dec = com.sun.mail.util.BASE64DecoderStream.decode(enc.getBytes()); //apache commons codec //dec = org.apache.commons.codec.binary.Base64.decodeBase64(enc); //自作Base64 dec = Base64.decode(enc); } long t2 = System.currentTimeMillis(); System.out.println(t2 - t); }
結果
エンコード
パッケージ | 時間 |
---|---|
sun mail util | 4166 |
apache commons codec | 9556 |
自作Base64 | 8042 |
デコード
パッケージ | 時間 |
---|---|
sun mail util | 4461 |
apache commons codec | 9284 |
自作Base64 | 7762 |
というわけで、速度的には一応使えそうです。ただ、なんだかバグがありそうな匂いがぷんぷんするので、要検証ですね。
- 参考
Base64 - Wikipedia
トラシスラボ 技術ブログ: ページが見つかりません。
javaのビット演算が非常に面倒でした。byte型をビット演算すると勝手にintに変換されるので要注意です。