# ja.pl ver0.03E-5 # JPEG(JFIF)専用 # JPEG(JFIF)のバイナリを解析する‥‥‥中途半端 # # 試作品 ver0.01E-5 # ファイルを配列化していたのを止める ver0.02E-5 # SEEKしてREADする仕様を止める ver0.03E-5 #======================================================================= # 実行速度計測 (試験用) #======================================================================= sub timetrial{ # 実行速度計測用 local ($user, $system, $cuser, $csystem); ($user, $system, $cuser, $csystem) = times; return($user,"秒\t+\t",$system,"秒\t=\t",($user + $system),"秒"); }# END timetrial #======================================================================= # 各種グローバル変数 #======================================================================= # 配列 master_marker_type_list(mmtl) は変換テーブル # SOF0 は 0xc0、十進数で192であるから、254-192=62個 # 0xff 0xXX を配列の添字とし'1'ならばマーカーである while($#mmtl<0xff){push(@mmtl, 0);} # -wオプション対策 @mmtl[0xc0 .. 0xfe] = ( 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 ); # 配列 master_marker_length_list(mmll) はlengthの判断用テーブル # 0xff 0xXX をし配列の添字とし'1'ならばlengthの無いマーカーである while($#mmll<0xff){push(@mmll, 0);} # -wオプション対策 @mmll[0xd0 .. 0xd9] = ( 1,1,1,1,1,1,1,1,1,1 ); # JFIFに規定される3文字の省略表記に因る @mmnl[0xc0 .. 0xfe] = ( "SOF", "SOF", "SOF", "SOF", "DHT", "SOF", "SOF", "SOF", "JPG", "SOF", "SOF", "SOF", "dAC", "SOF", "SOF", "SOF", "RST", "RST", "RST", "RST", "RST", "RST", "RST", "RST", "SOI", "EOI", "SOS", "DQT", "DNL", "DRI", "DHP", "EXP", "APP", "APP", "APP", "APP", "APP", "APP", "APP", "APP", "APP", "APP", "APP", "APP", "APP", "APP", "APP", "APP", "JPG", "JPG", "JPG", "JPG", "JPG", "JPG", "JPG", "JPG", "JPG", "JPG", "JPG", "JPG", "JPG", "JPG", "COM"); # JFIFに規定される3文字の省略表記に因る #@mmnnl[0xc0 .. 0xfe] = ( # "0", "1", "2", "3", "", "5", "6", "7", "", "9", "10","11","", "13","14", # "15","0", "1", "2", "3", "4", "5", "6", "7", "", "", "", "", "", "", # "", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10","11","12", # "13","14","15","0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10","11", # "12","13",""); undef $file_name; # 引数から分割したファイル名 undef $file_size; # ↑ファイルサイズ undef $bin_dat; # バイナリを収納 undef @marker_code; # 発見されたMARKERの16進数 undef @marker_position; # 発見されたMARKERの位置 #======================================================================= # メイン #======================================================================= main:{ # C風だとこうだが意味が無い print "user\t+\tsystem\t=\tTOTAL\n"; # TEST print "-----------------------------------------------------------------------\n"; print &timetrial,"\t開始\t",@ARGV,"\n"; # TEST if(@ARGV == 0){ print "ファイルが在りません\n"; exit; } # 後でコマンド説明を造っても面白い else{ foreach $file_name (@ARGV) { # 引数の処理 $file_size = (stat($file_name))[7]; # ファイルサイズ if($file_size==0){ die "ファイルが0 BYTE です\n"; } else{ open (IN ,$file_name); binmode(IN); # 開いて sysread(IN, $bin_dat, $file_size); # 変数に食わせる close (IN); # 用が済んだら閉じる print &timetrial,"\tINDEX取得開始\t","\n"; # TEST &meke_index; print &timetrial,"\tINDEX取得終了\t","\n"; # TEST print "-----------------------------------------------------------------------\n"; &maker_check(); # 個別のマーカーチェック関数 } } } }# END_main #======================================================================= # インデックス取得 関数 #======================================================================= sub meke_index{ undef (my @list); # 一時処理用の配列 in バイナリ my $i; my $j = 0; # 現在の読取位置の変数 while(1){ # 無限ループ if($j+1 > $file_size){last;} # マーカーはファイルサイズを越えない $list[0]=&bin_access($j, 1); # 1バイト目 if($list[0]==0xff){ # マーカーと推測 $list[1]=&bin_access($j+1, 1); # 2バイト目 if($mmtl[$list[1]]==1){ # マーカーと確定 if($mmll[$list[1]]==1){ # Lengthの値の無いマーカー if ($list[1]==0xd9){ # EOI の場合終了 push(@marker_code, $list[1]); push(@marker_position, $j); last; }else{ # SOI,RST0-RST7,SOS (EOI以外) push(@marker_code, $list[1]); push(@marker_position, $j); $j=$j+2; } }else{ # Lengthの値が在るマーカー ($list[2],$list[3]) = &bin_access($j+2, 2); # 3,4バイト目 $i = hex(sprintf("%02x", $list[2]).sprintf("%02x", $list[3])); push(@marker_code, $list[1]); push(@marker_position, $j); $j=$j+$i+2; # マーカー分だけ進める +2 } }else{ # マーカー以外と推定された処理 $j++; } }else{ # マーカー以外と確定された処理 $j++; } }# 無限ループ終端 }# END meke_index #======================================================================= # ファイルの検索位置からバイナリを16進数で返す #======================================================================= sub bin_access{ # 引数 (開始位置,長さ) undef (local $buffer); local $i = $_[0]; local $j = $_[1]; $buffer = substr($bin_dat, $i, $j); return unpack("C*",$buffer); # 配列に切分 }# END bin_access #======================================================================= # 各マーカー毎の関数の呼び出し制御 #======================================================================= sub maker_check{ my $num = 0; foreach $i (@marker_code){ eval( "&mark_"."$mmnl[$i]"."(".$num.")" ); $num++; } }# END maker_check #======================================================================= # SOF関数 #======================================================================= sub mark_SOF{ my $i=$_[0]; # @marker_codeの配列番号 my @coding = ( # 圧縮の配列 "Huffman Baseline DCT", # SOF0 "Huffman Extended Sequential DCT", # SOF1 "Huffman Progressive DCT", # SOF2 "Huffman LossLess DPCM Spatial", # SOF3 "", "Huffman Differential Extended Sequential DCT", # SOF5 "Huffman Differential Progressive DCT", # SOF6 "Huffman Differential LossLess DPCM Spatial", # SOF7 "", "Arithmetic Extended Sequential DCT", # SOF9 "Arithmetic Progressive DCT", # SOF10 "Arithmetic LossLess DPCM Spatial", # SOF11 "", "Arithmetic Differential Extended Sequential DCT", # SOF13 "Arithmetic Differential Progressive DCT", # SOF14 "Arithmetic Differential LossLess DPCM Spatial" ); # SOF15 my @color = ( # 色数 "", "256 MONOCHROME", "", "16,777,216" ); print "■ Start of frame segment(SOF)"."\n"; if(!($#marker_code-$i)==0){ print "\t"."シグメント長: ".($marker_position[$i+1]-$marker_position[$i])."バイト"."\n"; } print "\t".$coding[$marker_code[$i]-192]."\n"; ($list[0],$list[1],$list[2],$list[3],$list[4],$list[5]) = &bin_access($marker_position[$i]+4, 6); print "\t"."DCTサンプル精度: ".$list[0]."bit"."\n"; print "\t"."行数(高): ".hex(sprintf("%02x", $list[1]).sprintf("%02x", $list[2]))."pixel"."\n"; print "\t"."列数(幅): ".hex(sprintf("%02x", $list[3]).sprintf("%02x", $list[4]))."pixel"."\n"; print "\t"."色数: ".$color[$list[5]]."\n"; }# END mark_SOF sub mark_DHT{ my $i=$_[0];print "DHT"."\t"."$i"."\n"; } sub mark_dAC{ my $i=$_[0];print "dAC"."\t"."$i"."\n"; } sub mark_RST{ my $i=$_[0];print "RST"."\t"."$i"."\n"; } #======================================================================= # SOI関数 #======================================================================= sub mark_SOI{ my $i=$_[0]; # @marker_codeの配列番号 print "■ Start of Image(SOI)"."\n"; if(!($#marker_code-$i)==0){ print "\t"."シグメント長: ".($marker_position[$i+1]-$marker_position[$i])."バイト"."\n"; } } #======================================================================= # EOI関数 #======================================================================= sub mark_EOI{ my $i=$_[0]; # @marker_codeの配列番号 print "■ End of Image(EOI)"."\n"; print "\t"."シグメント長: 2バイト"."\n"; # 決め打ち...(T_T) } sub mark_SOS{ my $i=$_[0];print "SOS"."\t"."$i"."\n"; } #======================================================================= # DQT関数 #======================================================================= sub mark_DQT{ # DQTの取出方の問題 # # DQTは64基である。 # DQTは8bit,16bitの二種類、1バイトか2バイトであるかの違いが在る。 # もし、シグメント長-4が65以上ある場合 # DQTが1基以上含まれていると言う事。 my $i=$_[0]; print "■ Define quantization table segment(DQT)"."\n"; if(!($#marker_code-$i)==0){ print "\t"."シグメント長: ".($marker_position[$i+1]-$marker_position[$i])."バイト"."\n"; } my @table_al = ("8bit", "16bit"); # TABLEの単位 my $sl = ($marker_position[$i+1]-$marker_position[$i])-4; # シグメントの長さを収納 my $x = $marker_position[$i]+4; # ポジション while(1){ if($sl>=65){ # 8bit TABLE用 print "\t"; print "ELEMENT精度: "; print $table_al[int(&bin_access($x, 1)/16)]; print "\n"; print "\t"; print "量子化TABLE識別子: TYPE"; print int(&bin_access($x, 1)%16); print "\n"; print "\t量子化TABLE:\n"; if(int(&bin_access($x, 1)/16)==0){ $x++; for($j=0;$j<64;$j=$j+8){ print "\t"; for($g=0;$g<8;$g++){ print " ".sprintf("%02X", &bin_access($x+$j, 1));$x++; } print "\n"; } $sl = $sl-65; # print $sl."\n"; }elsif(int(&bin_access($x, 1)/16)==1){ # 16bit TABLE用 $x++; for($j=0;$j<64;$j=$j+8){ print "\t"; for($g=0;$g<8;$g++){ print " ".sprintf("%02X", &bin_access($x+$j, 1).&bin_access($x+$j+1, 1));$x=$x+2; } print "\n"; } $sl = $sl-129; } }else{last;} } } sub mark_DNL{ my $i=$_[0];print "DNL"."\t"."$i"."\n"; } sub mark_DRI{ my $i=$_[0];print "DRI"."\t"."$i"."\n"; } sub mark_DHP{ my $i=$_[0];print "DHP"."\t"."$i"."\n"; } sub mark_EXP{ my $i=$_[0];print "EXP"."\t"."$i"."\n"; } #======================================================================= # APP関数 #======================================================================= sub mark_APP{ my $i=$_[0]; # @marker_codeの配列番号 print "■ Application(APP)"."\n"; if(!($#marker_code-$i)==0){ print "\t"."シグメント長: ".($marker_position[$i+1]-$marker_position[$i])."バイト"."\n"; } my $f_name = "";my $j = 4;$k = 0; while(1){ $k = &bin_access($marker_position[$i]+$j, 1); if($k==0x00){ if($f_name =~ /Photoshop/ || $f_name =~ /Adobe/ || $f_name =~ /ICC_PROFILE/){ print "\t"."FORMAT: ".$f_name."\n"; last; }else{ $f_name = $f_name." "; $f_name = $f_name.sprintf("%d", &bin_access($marker_position[$i]+$j+1, 1)); $f_name = $f_name."."; $f_name = $f_name.sprintf("%02d", &bin_access($marker_position[$i]+$j+2, 1)); print "\t"."FORMAT: ".$f_name."\n"; my @scale_table = ("(?)", "inch", "cm"); my $scale = $scale_table[&bin_access($marker_position[$i]+$j+3, 1)]; print STDOUT ("\t"."水平密度: ". sprintf("%2d", &bin_access($marker_position[$i]+$j+4, 1).&bin_access($marker_position[$i]+$j+5, 1)). " ".$scale."\n"); print STDOUT ( "\t"."垂直密度: ". sprintf("%2d", &bin_access($marker_position[$i]+$j+6, 1).&bin_access($marker_position[$i]+$j+7, 1)). " ".$scale."\n"); if(!($marker_position[$i+1]-$marker_position[$i])==18){ print STDOUT ( "\t"."サムネイル行数(高): ". sprintf("%2d", &bin_access($marker_position[$i]+$j+8, 1))." Pixel\n"); print STDOUT ( "\t"."サムネイル列数(幅): ". sprintf("%2d", &bin_access($marker_position[$i]+$j+9, 1))." Pixel\n"); # シグメント長が18バイトを越える場合サムネイル画像を含むと推測される # 実際のサムネイル画像が手元に無い為に未検証 } last; } }else{ $f_name = $f_name.pack("c*", $k); $j++; } } } sub mark_JPG{ my $i=$_[0];print "JPG"."\t"."$i"."\n"; } #======================================================================= # COM関数 #======================================================================= sub mark_COM{ my $i=$_[0]; # @marker_codeの配列番号 print "■ Comment(COM)"."\n"; if(!($#marker_code-$i)==0){ print "\t"."シグメント長: ".($marker_position[$i+1]-$marker_position[$i])."バイト"."\n"; } my @j = &bin_access(($marker_position[$i]+4), (($marker_position[$i+1]-$marker_position[$i])-4)); print "------------"."\n"; print pack("c*", @j); print "------------"."\n"; }