Rubyプログラミング

Rubyプログラミング(3)


1.バイナリーファイルの扱いに関連した話

ニュースのところで紹介した本、OS自作入門で遊んでいます。30日で何かができるというところがいいですよね。洋書だとSAMS PublishingのTeach Yourselfシリーズというのがあって、いろんな種類の教本が24時間や一週間で学習できるように書かれています。

さて、OS自作入門では1.44MBのフロッピーディスクのイメージファイルを作成するところから話が始まっています。BZエディタでブートセクタにデータを入力した後でひたすら00のデータを埋めていくことになります。

これでは、ちょっと大変なのでrubyで1.44MBフロッピーディスクのイメージファイルのテンプレートを作ってみましょう。テンプレートといっても全部00で埋まっているだけです。

それでは、何回00(1バイト分)でデータを埋めればイメージファイルを作れるのでしょうか。フロッピーディスクの構造を知る必要があります。次の決まりに従って考えてみましょう。

・フロッピーディスクには表と裏に情報を書き込む
・表にはトラックと呼ばれる同心円がある。1.44MBフロッピーディスクの場合、トラックの数は80である。
・一つのトラックはさらにセクタという部分に分かれている。1.44MBフロッピーディスクの場合、セクタの数は18である。
・1.44MBフロッピーディスクの場合、1セクタのバイト数は512バイトである。

ここまでくればイメージファイルの全バイト数が求められそうです。Windowsのアクセサリに入っている電卓などを使ってイメージファイルに必要なバイト数を計算してみよう。式は次のようになります。*は掛け算を表します。

2*80*18*512

従ってイメージファイルは1474560バイト必要だということがわかります。この値を使って繰り返し00の値をファイルに書き込んでいくことになります。

練習1.1474560を16進数で表現してみましょう。電卓なども利用できます。

そのための準備としてまず次のプログラムを試してみましょう。image1.rbとして保存しておきましょう。

5.times{
  print 0
} 

このプログラムは0を5つ表示します。ruby以外のプログラムではfor文などを使って繰り返しを表現しますが、rubyでは数値もオブジェクトとして考えられていて、そのメソッドtimesを使用して繰り返しを表現することができます。繰り返しは{ }で囲まれたブロック内のプログラムに対して行われています。

次にバイナリファイルに出力してみましょう。次のようにプログラムを書き変えてみましょう。

File.open("test.img","wb"){|file|
  5.times{
    file.write 0
  }
}

Fileクラスのopenメソッドを使用しています。出力ファイル名test.imgを指定しています。wbのwは書きこみ、bはバイナリモードを指定しています。次のブロック内でブロック変数|file|を与えていますが、これはtest.imgを指していると考えてください。このfileに対してwriteメソッドを使用することができますので、これを使ってファイルtest.imgに0を5つ書いていくことになります。

では実行してみましょう。test.imgファイルが出力されたでしょうか。dirコマンドでファイル名があることを確認するとよいでしょう。次に中身を確認してみます。紹介した本でも使用しているBZというバイナリエディタを使用してみます。次のURLにバイナリエディタのリストがあるので、ここからBZを選んでダウンロードしてみるといいでしょう。また、他にもいろいろなものがあります。

http://www.vector.co.jp/vpack/filearea/win/util/bin/edit/index.html

BZを起動してファイルの開くからさきほど作ったtest.imgを開いてみます。

        +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF
000000  30 30 30 30 30                                   00000

上記のように30という値が入ってしまいます。これは0が文字のコードとして認識されているためです。00として扱うためにはrubyでは"\x00"のように表現します。これをもとにプログラムを書き直してみます。

File.open("test.img","wb"){|file|
  5.times{
    file.write "\x00"
  }
}

これを実行してみましょう。BZは一度終了して起動し直してください。test.imgを開いてみます。

        +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF
000000  00 00 00 00 00                                   .....

今度はきちんとデータが入っているようです。ここまで準備ができたらいよいよイメージファイルのテンプレートを作ります。要は1474560回、繰り返しを行わせるだけですから、プログラムは次のようになります。

File.open("fd144.img","wb"){|file|
  1474560.times{
    file.write "\x00"
  }
}

出力ファイル名をfd144.img、繰り返し回数を1474560として00を出力しています。BZで確認すると

           +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF
0000:0000  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

から

           +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF
0016:7FF0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0016:8000

まで00で埋まっていることになります。

練習2.確認です。0000:0000から0016:8000まで何バイトあるでしょうか。計算して確認してみましょう。電卓を使うのもいいでしょう。

ここからあとはrubyそのものの話とは関係がないので、OS自作本などを参考にして、BZを使用して0000:0000から0000:01ffまでをブートセクタの規則に従って埋めていくことになります。さらに

           +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF
0016:0200  F0 FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

           +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F  0123456789ABCDEF
0016:1400  F0 FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

に、上記のようにFATの先頭の情報も入れておきます。それから完成したイメージファイルをrawwritewin.exeなどを使用し、フロッピーディスクに書き込みます。

このようにイメージファイルを用意することで、フロッピーディスクから起動してプログラムを実行させることができます。ただし、トラブルを伴うこともあるので自分の責任において作業を進めるようにしてください。