SWFファイルのヘッダ

とーとつにFlashに興味が沸いたので手始めにヘッダを解析してみた。
問題なのは興味の対象がFlashであってASではないところだ。

#! ruby -Ks
require 'zlib'

class SWF
  attr_reader :version, :length, :x_min, :x_max, :y_min, :y_max, :frame_rate, :frame_count

  def initialize(filename)
    # swfファイルの読み込み
    open(filename, 'rb') do |fh|
      @bin = fh.read
    end

    # シグネチャ判定
    case @bin[0, 3]
      when 'CWS' # CWS(圧縮形式)であれば展開してFWSに変換する
        @bin = 'F' + @bin[1, 7] + Zlib::Inflate.inflate(@bin[8..-1])
      when 'FWS' # FWS(通常形式)であればそのままにする
        # 処理なし
      else
        raise "swf形式のファイルではありません"
    end

    # バージョン情報
    @version = @bin[3, 1]

    # ファイルの長さ
    @length = @bin[4, 4].unpack('V')[0]

    # ヘッダのRECT型
    nbits = @bin[8, 1].unpack('B*')[0].to_s[0, 5].to_i(2)
    rect_size = (nbits * 4 + 5 + 7) / 8
    rect = @bin[8, rect_size].unpack('B*')[0].to_s[5..-1]
    @x_min = rect[0, nbits].to_i(2)
    @x_max = rect[nbits, nbits].to_i(2)
    @y_min = rect[nbits * 2, nbits].to_i(2)
    @y_max = rect[nbits * 3, nbits].to_i(2)

    # フレームレート
    @frame_rate = @bin[8 + rect_size, 2].unpack('v')[0] / 256.0

    # フレーム数
    @frame_count = @bin[8 + rect_size + 2, 2].unpack('v')[0]
  end
end

swf = SWF.new('Hello.swf')

puts "version     : #{swf.version.unpack('C')[0]}"
puts "length      : #{swf.length}"
puts "x_min       : #{swf.x_min}"
puts "x_max       : #{swf.x_max}"
puts "y_min       : #{swf.y_min}"
puts "y_max       : #{swf.y_max}"
puts "frame_rate  : #{swf.frame_rate}"
puts "frame_count : #{swf.frame_count}"

#=>
# version     : 9
# length      : 905
# x_min       : 0
# x_max       : 10000
# y_min       : 0
# y_max       : 7500
# frame_rate  : 24.0
# frame_count : 1