Base64をデコードしてみました
プログラム上で処理しなければならないことは色々ありますが
クラスライブラリとして提供されるものも多いので、上手に活用するのが早道です。
毎度、管理人イガジーです。
でも、プログラミングの練習としては、変換処理のひとつふたつは
作ってみるのが良いでしょう。
という訳で、Base64 のデコード処理を自前で作ってみました。
Base64については、Wikipediaに詳しい説明があります。→こちら
要するに、A〜Z, a〜z, 0〜9 の文字(+2文字)で、6ビットデータを表す
ようにしたものがBase64です。
デコードは、このA〜Z, a〜z, 0〜9 の文字からもとの8ビットデータに戻すことです。
例えば、QUJDREVGRw== をデコードすると ABCDEFG になります。
まず、それらの文字を6ビットデータに変換する処理を考えます。
int dec1(int x){ // 6bits
int r=0;
switch (x) {
case '+':
case '-':
r=62;break;
case '/':
case '_':
r=63;break;
case '=':r=0;break;
default:
if ((x>='A')&&(x<='Z')) r=x-'A';
else if ((x>='a')&&(x<='z')) r=x-'a'+26;
else if ((x>='0')&&(x<='9')) r=x-'0'+52;
// else System.out.print("Err ");
break;
}
return r;
}
if 文が処理の中心です。
書き方によっては && を使わないようにすることもできますが
分かりやすさを優先しました。
switch〜caseを使わずに、全部 else if で書いてしまうこともできます。
好みですが、switch〜caseの方が、62,63 の文字を変更しやすいと
思ったので上記の書き方にしました。
さて、次は6ビットを8ビットにはめ込む処理です。つまり
123456 123456 123456 123456
を
12345612 34561234 56123456
にするのですが、4つの6ビットを3つの8ビットにする処理をベタで書き下すことにします。
その場合に面倒なのが、4つずつ処理しようとしても、3つしか無いとか
2つしかない、という場合の異常処理です。
毎回チェックするのも面倒なので、最初に入力データに3つぶんの”===”を
足しておくことにします。
入出力は、普通ファイルなのでしょうが、手軽さを考えて引数で入力し
printfで出力する形にしました(改造はご自由に)。
public class Base64Dec {
int d[]=new int[3];
int dt;
Base64Dec(String as[]){
for (int i=0;i<as.length;++i) {
System.out.println(as[i]);
String t=as[i]+"===";
for (int j=0;j<as[i].length();j+=4) {
// 12345612 34561234 56123456
// QUJDREVGRw==
// ABCDEFG
d[0]=(dec1(t.charAt(j))*4)&0xFF; // <<2
dt=dec1(t.charAt(j+1));
d[0]+=(dt/16); // >>4
d[1]=(dt*16)&0xFF; // <<4
dt=dec1(t.charAt(j+2));
d[1]+=(dt/4); // >>2
d[2]=(dt*64)&0xFF; // <<6
d[2]+=dec1(t.charAt(j+3));
for (int k=0;k<3;++k) {
System.out.printf(" %02X", d[k]);
if ((d[k]>' ')&&(d[k]<'z')) System.out.printf("(%c)", d[k]);
}
}
}
}
int dec1(int x){ // 6bits
int r=0;
switch (x) {
case '+':
case '-':
r=62;break;
case '/':
case '_':
r=63;break;
case '=':r=0;break;
default:
if ((x>='A')&&(x<='Z')) r=x-'A';
else if ((x>='a')&&(x<='z')) r=x-'a'+26;
else if ((x>='0')&&(x<='9')) r=x-'0'+52;
// else System.out.print("Err ");
break;
}
return r;
}
/*
void printbin6(int x) {
int m=0x20;
for (int i=0;i<6;++i) {
if ((x & m)!=0) System.out.print("1");
else System.out.print("0");
m=m/2;
}
System.out.print(" ");
}
void printbin8(int x) {
int m=0x80;
for (int i=0;i<8;++i) {
if ((x & m)!=0) System.out.print("*");
else System.out.print("_");
m=m/2;
}
System.out.print(" ");
}
*/
public static void main(String[] args) {
new Base64Dec(args);
}
}
printbin8(), printbin6() はデバッグ用の2進数表示メソッドです。
上記を眺めるだけでなく、ぜひエンコードも作ってみてください。
この記事へのコメントはこちら