D03: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";
出力するデータがダウンロードする形式である事を出力します。
$file[0]=~s/[^0-9a-fA-F]//g;
$file[0]=~s/([0-9a-fA-F][0-9a-fA-F])/pack("C",hex($1))/eg;
送られてきた16進数表示のテキストをバイナリデータに変換しています。
☆今回のポイント☆
16進数表示のテキストをバイナリデータに変換しよう!
print $file[0];
変換したバイナリデータを出力しています。
exit;
プログラムを終了させます。