MediBangファイルフォーマットの解析(C言語で情報抽出)

続きです。

C言語で、バイナリデータを読み込むプログラムを作りたいと思います。

最初に、引数で指定したmdpファイルを読み込む簡単なプログラムから。

takk@deb8:~/Desktop$ cat -n read-mdp.c
     1	#include <stdio.h>
     2	
     3	int main(int argc, char* argv[])
     4	{
     5		int c;
     6		int n = 0;
     7		FILE *fp = fopen(argv[1], "r");
     8	
     9		while((c = fgetc(fp)) != EOF){
    10			n ++;
    11		}
    12		printf("length:%d\n",n);
    13	
    14		return 0;
    15	}
takk@deb8:~/Desktop$ gcc t.c
takk@deb8:~/Desktop$ ./a.out file-1.mdp
length:2061
takk@deb8:~/Desktop$ wc -c file-1.mdp
2061 file-1.mdp
takk@deb8:~/Desktop$ 

簡単なファイル読み込みのプログラムが確認できたら、PAC文字列を探す処理を入れてみます。
連続4回照合成功したら、情報を表示してプログラムを終了する処理です。

takk@deb8:~/Desktop$ cat -n read-mdp.c
     1	#include <stdio.h>
     2	
     3	int main(int argc, char* argv[])
     4	{
     5		char ptn[] = "PAC ";
     6		int c,len;	
     7		int n = 0;
     8		int ind = 0;
     9		FILE *fp = fopen(argv[1], "r");
    10	
    11		while((c = fgetc(fp)) != EOF){
    12			if((char)c == ptn[ind])
    13				ind++;
    14			else
    15				ind=0;
    16			n ++;
    17			if(ind == 4){
    18				ind = 0;
    19				len = fgetc(fp);
    20				len |= fgetc(fp) << 8;
    21				printf("index:%x length:%d\n", n - 4, len);
    22				break;
    23			}
    24		}
    25		return 0;
    26	}
takk@deb8:~/Desktop$ gcc read-mdp.c
takk@deb8:~/Desktop$ ./a.out file-1.mdp
index:528 length:333
takk@deb8:~/Desktop$ 

最後にfseekでファイルポインタの位置を次のブロックまで移動させて、すべてのPAC文字列の位置と各データの長さを表示するプログラムにします。データ長2バイトでは足りないかもしれませんが。

takk@deb8:~/Desktop$ cat read-mdp.c
     1	#include <stdio.h>
     2	
     3	int main(int argc, char* argv[])
     4	{
     5		char ptn[] = "PAC ";
     6		int c,len;	
     7		int n = 0;
     8		int ind = 0;
     9		FILE *fp = fopen(argv[1], "r");
    10	
    11		while((c = fgetc(fp)) != EOF){
    12			if((char)c == ptn[ind])
    13				ind++;
    14			else
    15				ind=0;
    16			n++;
    17			if(ind == 4){
    18				ind = 0;
    19				len = fgetc(fp);
    20				len |= fgetc(fp) << 8;
    21				printf("index:%x length:%d\n", n - 4, len);
    22				fseek(fp, len - 6, SEEK_CUR);
    23				n += len - 4;
    24			}
    25		}
    26	
    27		return 0;
    28	}

実行すると、おそらく画像データであろうPACブロックの位置とデータ長が取得できます。

takk@deb8:~/Desktop$ gcc read-mdp.c
takk@deb8:~/Desktop$ ./a.out file-1.mdp
index:528 length:333
index:675 length:136
index:6fd length:136
index:785 length:136
takk@deb8:~/Desktop$ ./a.out file-2.mdp
index:528 length:333
index:675 length:136
index:6fd length:248
index:7f5 length:136
takk@deb8:~/Desktop$ 
takk@deb8:~/Desktop$ strings -tx file-1.mdp | grep PAC
    528 PAC M
    675 PAC 
    6fd PAC 
    785 PAC 
takk@deb8:~/Desktop$ strings -tx file-2.mdp | grep PAC
    528 PAC M
    675 PAC 
    6fd PAC 
    7f4 iPAC 
takk@deb8:~/Desktop$ 

最後が7f4となっていますが、文字列PACの一つ前の文字からのオフセットとなっているためです。

では、もう少し大きなデータで試してみます。

takk@deb8:~/Desktop$ ls -l summerwars.mdp 
-rw-r--r-- 1 takk takk 4709500  2月 28 05:55 summerwars.mdp
takk@deb8:~/Desktop$ 
takk@deb8:~/Desktop$ ./a.out summerwars.mdp 
index:3fe length:13430
index:23874 length:4372
index:414988 length:37620

サイズが合いません。データ長が2BYTEではやはり足りなかったです。

takk@deb8:~/Desktop$ od -tx1 -j 0x23874 -N 10 summerwars.mdp 
0434164 50 41 43 20 14 11 3f 00 00 00
0434176
takk@deb8:~/Desktop$ ruby -e 'printf "%x", 0x3f1114 + 0x23874'
414988

埋め込まれたデータ長が4バイトと仮定して計算すると、数字が合うので、おそらく各PACブロックのデータ長は4バイトなのでしょう。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA