はじめに

  • {header}+{header_movie}+{tag block}+{tag block}+.... といった形式
  • {header}が固定長。{header_movie}が描画領域フィールドだけ可変長
  • {tag block} は { tag | length | contents.... } # いわゆる TLC構造
  • 複数バイトで表現する値が LittleEndian なのと、一部、ビット単位でフィールドが詰まっている事が分かれば、後は素直な形式なので楽に分解できる。
  • block の中身(contents)も興味があるものだけ解析すればOKなので、中身を入れ替える場合は、入れ替えた {tag block}の length と {header}にある file_length の2箇所を更新すれば大抵のブロックは入れ替えられる。

header

+--------------------------------+
|  magic  | ver  |  file_length  |
+--------------------------------+
<-3 bytes-><1 byte><-- 4 bytes -->

magic: offset = 0

  • FWS or CWS の 3文字 + SWF version (1 byte)
  • CWS の時は、file_length の後ろ(=header_movie 以降全て)のデータが zlib 圧縮される
+-----------------------------------------------------------------+
|  FWS\0   | ver  |  file_length  | header_movie | tag_block list |
+-----------------------------------------------------------------+
<-3 bytes-><1 byte><-- 4 bytes -->
                                    ↓zlib compress↓
+--------------------------------------------------+
|  CWS\0   | ver  |  file_length  |  (compressed)  |
+--------------------------------------------------+
                                   ↑ compressed
                                      header_movie & tag_block list

file_length: offset = 4

  • Little Endian 4 byte
  • SWF ファイル全体の byte 数

header_movie

char align (byte境界に合わせる)
   |
   +-------------------------------------------------------
   | size  |  x_min   |  x_max   |  y_min   |  y_max   | ..
   +-------------------------------------------------------
   <5 bits><size bits><size bits><size bits><size bits>
 -------------------------------------+
 .. |  frame_rate  | frame_rate_count |
 -------------------------------------+
     <-- 2 bytes --> <--  2 bytes  -->

size: offset = 8

  • 先頭 5 bits は、この後に続く {x,y}_{min_max} のフィールドサイズ(つまり可変長)

{x,y}_{min,max}: offset = 8 + 5(bits) + n*size(bits) (n は 0 数え)

  • 表示フレームの左上と右下の座標値 (単位は TWIPS)
  • 負の値もとりうる事に注意。

frame_rate: offset = 8 + 5(bits) + 4*size(bits)

  • frame_rate
  • little endian の 8.8固定小数点なので、0x100 倍相当の値が byte swap して入っている

frame_rate_count: offset = 8 + 5(bits) + 4*size(bits) + 2

  • frame_rate_count: frame 数

tag block

  • header + header_movie の後ろに TLC(Type|Length|Contents)形式で並ぶ
+----------------------------------------------------+
| header | header_movie | tag_block | tag_block| ... |
+----------------------------------------------------+
<-8bytes-> <- 可変長 ->   <- 可変長 -- 数も可変 --
  • tag block は contents の長さ(length)によって二種類のフォーマットに分かれる

tag block の構造 (1) length < 0x3f

+-------------------------------------+
|  tag    | length |     contents     |
+-------------------------------------+
<-10bits-><-6bits-><-- length bytes -->
<- Little Endian ->
  • tag & length は Little Endian なので
    +--------------+------------+
    | tag | length |    tag     |
    | 1 0 | 543210 |  98765432  |
    +---------------------------+
    • bit 構成的には↑こんな感じ。(ややこしい)

tag block の構造 (1) 0x3f <= length or something

+------------------------------------------------------+
|  tag   |  0x3f   |    length    |      contents      |
+------------------------------------------------------+
<-10bits-><-6bits-><-- 4 bytes --> <-- length bytes -->
<- Little Endian ->
  • DefineBitJpeg* のように length の値に関係なく(0x3f 以下でも)このフォーマットを使う tag があるので注意。

tag contents の構造

(0) End

  • SWF ファイルの末尾に来る tag は必ずこれ
    +--------------+
    | tag | length |
    |  0  |    0   |
    +--------------+
    <-  2 bytes  ->

(6, 21, 35, 90) DefineBitsJPEG*

(8) JPEGTables

(20, 36) DefineBitsLossless*

(37) DefineEditText

(39) DefineSprite

(2, 22, 32, 46, 83, 84) DefineShape*

(12, 59) Do*Action