Swf渲染之——文件结构
上一节我们下载了Swf文件,现在我们来尝试阅读它,使用ffd(JPEXS Free Flash Decompiler)来打开这个文件,我们可以看到Swf文件的结构如下:

其中有
形状:Swf文件中最重要的元素之一,主要用于存储矢量图形数据。形状可以是简单的几何图形,也可以是复杂的重叠元素变形形状:一类特殊的形状,内部有开头和结尾两份矢量数据,在精灵的引用中,通过设置ratio字段来控制变形进度,示例swf中没有这类形状精灵:Swf文件中另一个重要的元素,主要用于存储动画数据。精灵本身不存储图形数据,而是通过引用形状和其他元素来实现动画效果,内部有独占的帧序列图像:一些位图数据,可用于形状的内部填充帧和场景:定义了swf文件在默认直接播放时,渲染的动画帧序列,在这个swf例子中,只有一个空白帧其他:一些其他元素,比如定义背景的颜色,不同场景的起始帧,精灵的名称等脚本:没啥好说的,配合脚本,swf文件就能成为一个完整的程序,但本专栏暂不涉猎
对于大部分开发者来说,这样理解足够了,但是我们为了解读swf,必须换一个角度,点击右上角的16进制转储

我们可以看到这样的画面

文件头
可以发现,swf文件内部首先是几条header信息,被称为文件头,但是在具体的读取的时候,需要注意文件头是被分割的,format,version,file_length被我称为SwfFileInfo,frame_size,frame_rate,frame_count被我称为SwfHeader,如图

其中
-
format:文件格式,在官方文档中,被定义为3个Signature,每个Signature都是一个UI8,即一个无符号字节,存储一个字符。这里最重要的是第一个Sig,标志了这个swf的压缩信息- 'F':表示文件是未压缩的
- 'C':表示文件是使用Zlib压缩的
- 'Z':表示文件是使用LZMA压缩的
后面的两个则永远是'W'和'S',不重要
-
version:版本号,也是UI8,直接存储数值而不是字符,0x06表示第6版 -
file_length:文件长度,UI32,存储文件的总字节数,用于和解压之后的文件长度进行对比,验证文件是否完整 -
frame_size:帧大小,RECT1,存储帧的宽度和高度,单位是Twips,1 像素 = 20 Twips -
frame_rate:帧率,UI16,存储帧率,单位是帧/秒 -
frame_count:舞台帧数,UI16
标签
之后就是元信息标签和一系列定义标签,这些标签都继承于Tag,符合Tag的基本格式。
在官方定义中,Tag是一个基类,每个Tag都有一个Header,定义如下

要注意,虽然TagTagCodeAndLength看起来像两个字段,但是存储方式是UI16,必须一次读完然后移位操作,这是因为swf使用小端序,在硬盘中低位在前
TagCode:高10位,表示标签的类型TagLength:低6位,表示标签的长度- 然后是一个假想的
TagData:标签的具体数据,长度是TagLength,单位是字节,在不同的Tag中对应不同的具体字段
聪明的小伙伴肯定会想:这6位的TagLength也太短了,最多也就63,tag一大不就无法描述了么?
所以!SWF的Tag Header还有另一种格式!如下:

这种长类型有一个专门的Length字段,UI32,能存储整整2GB的标签长度。
—— 根据
TagLength的值是否为极限值来判断,如果TagLength的值是63,则认为是长Tag,需要进一步读取Length字段作为真正的长度
SetBackgroundColorTag
让我们来实战演练一下吧,让我们看看第二个2Tag在16进制下长什么样子:

一串16进制数字, 43 02 99 99 99
其中 43 02 是 Header部分,由于swf用的是小端序,所以真实的值为 02 43
换算成二进制就是 0000 0010 0100 0011
高10位换算回10进制是9,也就是SetBackgroundColorTag的枚举值
低十位换算成10进制是3,3 < 63,也就是说后面还有3个字节
于是我们就确定了这个Tag的具体类型为SetBackgroundColorTag,先看看官方定义:

很明显,这个Tag很简单。除了TagHeader只有一个固定的RGB3值,其长度正好与之前读到的3相等。那么剩下的99 99 99也就很好理解了:
一个RGB(0x99, 0x99, 0x99)的结构体。换算成10进制,就是RGB(153, 153, 153)
看一眼FFD的结果:

果然,分毫不差!
注
RECT是一个变长结构体,定义如下

其中
Nbits是一个很关键的字段,表示后续字段的bits长度。本身的长度是UB[5],也就是5个bits- 如果
Nbits=5,那么后续字段的bits长度就是5,Xmin,Xmax,Ymin,Ymax每一个的长度就是5,一共是20bits,加上Nbits=5,结构体的长度总共是20+5=25 bits。 - 在示例文件中
Nbits=16, 所以Xmin,Xmax,Ymin,Ymax的长度是16bits,一共是64bits,整个是64+5=69 bits
- 如果
- Xmin,Xmax,Ymin,Ymax:四个
SB[Nbits],表示帧的最小和最大坐标值,单位是Twips
之所以不用FileAttributesTag是因为这个Tag在动画渲染方面用处不大且太复杂
RGB是一种颜色的存储方式,用红绿蓝三个通道表示颜色,不支持透明度,在swf中定义如下
每个通道一个字节,范围0~255,共3字节,24bit。