D02:バイナリデータを16進数表示のテキストに変換する
Perlはテキストの編集に有効な言語ですが、場合によってはバイナリデータを扱いたい時もあると思います。
今回は、バイナリデータを16進数表示のテキストに変換するようなCGIを紹介します。
ブラウザ上で使用可能なバイナリエディタの機能の一部を実現しているようなものだと思います。
ファイルを開く
解説
#!/usr/local/bin/perl
プロバイダがPerlを置いている場所を記述します。
ここでは/usr/local/bin/perlにあるとしています。
$max=1;
送られてくるデータの数を$maxに代入しています。
データはファイル以外も可能です。
$size=$ENV{'CONTENT_LENGTH'};
送られてきたデータのサイズを$sizeに代入しています。
ただし、複数のデータが決まったフォーマットに従ってまとめて送られてくる為、実際にはデータ本体以外の部分も合わせたサイズになっています。
if($size>1024*1024){
exit;
}
送られてきたデータのサイズが1MBより大きい場合にはプログラムを終了しています。
送られてきたデータがあまりにも大き過ぎると色々と不都合があるので、ここでは1MBに制限しています。
binmode(STDIN);
送られてくるファイルの種類を特に決めていないので、バイナリデータとして扱う為にbinmode(STDIN)を書いています。
while($size){
$len=sysread(STDIN, $buf, $size);
if($len==0){
last;
}
$size=$size-$len;
$data=$data.$buf;
}
送られてきたデータを$dataに代入しています。
$x=index($data,"\r\n");
$cut=substr($data,0,$x);
$cut="\r\n".$cut;
複数のデータが送られてくる場合、特定の文字列で区切られています。
その区切りの文字列を$cutに代入しています。
for($i=0;$i<$max;$i++){
$x=index($data,"\r\n\r\n")+4;
$filename[$i]=substr($data,0,$x);
$filename[$i]=~s/\n//g;
$filename[$i]=~s/.*filename="//;
$filename[$i]=~s/".*//;
$filename[$i]=~s/.*\\//g;
$filename[$i]=~s".*/""g;
$y=length($data);
$data=substr($data,$x,$y-$x);
$x=index($data,$cut);
$y=length($data);
$file[$i]=substr($data,0,$x);
$data=substr($data,$x+2,$y-$x-2);
}
$maxの数だけ送られてきたデータを$file[xx]に代入しています。
データがファイルの場合はファイル名が$filename[xx]に代入されます。
xxに入る数字は0〜$max-1の数字になります。
binmode(STDOUT);
出力するデータをバイナリ形式で扱うのでbinmode(STDOUT)を書いています。
print "Content-type:application/octet-stream\n";
print "Content-Disposition:attachment;filename=b2t_$filename[0]\n\n";
出力するデータがダウンロードする形式である事を出力します。
@a=unpack("C*",$file[0]);
送られてきたデータを@aという配列に1バイトずつ格納しています。
☆今回のポイント☆
バイナリデータを1バイト単位の配列として扱おう!
for($i=0;$i<=$#a;$i++){
printf("%02X",$a[$i]);
if((($i+1)%16)==0){
printf("\r\n");
}else{
printf(" ");
}
}
配列を16進数表示のテキストとして出力しています。
exit;
プログラムを終了させます。