swf文件格式解析入门(文件头解析)
2010-12-02 10:49

这里是使用as3语言来对swf文件做解析,其它语言可以参考。

一,准备工作
从Adobe官网下载一份swf文件格式说明文档
http://www.adobe.com/content/dam/Adobe/en/devnet/swf/pdf/swf_file_format_spec_v10.pdf
avm2虚拟机说明文档
http://www.adobe.com/content/dam/Adobe/en/devnet/actionscript/articles/avm2overview.pdf

采用flash builder新建一个项目。
// 嵌入测试的swf资源
[Embed (source = "../testswf/test.swf", mimeType = "application/octet-stream")]
private var content:Class;

// 初始化字节对象
var bytes:ByteArray = new content() as ByteArray;
// 设置为主机字节序
bytes.endian = Endian.LITTLE_ENDIAN;

二,开始解析工作
swf文件格式为:[header][FileAttributes tag][Tag][Tag]...[Endtag]
我们首先来解析header部分,如果这个部分会解析了,下面就很顺利了。
由于以上的文档都是flash player 9.0的时候写的,有部分10的特性没写在里面。
解析的时候如果遇到未知的类型,可以网上查查

1,解析文件头
swf文件是采用主机字节序

SWF File Header
Field           Type            Comment
Signature       UI8             Signature byte:
                                “F” 未压缩
                                “C” 压缩
Signature       UI8             固定为“W”
Signature       UI8             固定为“S”
Version         UI8             版本号 (如: 0x06 表示swf6)
FileLength      UI32            该swf文件的长度,单位:字节
FrameSize       RECT            swf的舞台大小,单位:twips 1px = 20twips
FrameRate       UI16            帧率,这里总共有16位,只有后面8位有效
FrameCount      UI16            总帧数

先读取3个字节的文件头
var sign:String = bytes.readUTFBytes(3);
if (sign != 'CWS' && sign != 'FWS')
    throw new Error ("文件头错误");
读取文件版本
version = bytes.readByte();
读取文件长度
fileLength = bytes.readInt();

如果文件签名是CWS,即是压缩过的,则需要进行解压缩
解压缩是从FrameSize这个地方开始到文件末尾
if (sign == 'CWS'){
    var tempBytes:ByteArray = new ByteArray();
    tempBytes.writeBytes(bytes, bytes.position);
    tempBytes.uncompress();
   
    var temp:int = bytes.position;
    bytes.length = bytes.position;
    bytes.writeBytes(tempBytes);
    tempBytes.length = 0;
    bytes.position = temp;
}

然后读取FrameSize

Bit Values 格式
Type        Comment
SB[nBits]   有符号位值 (nBits表示用多少位来存储这个值)
UB[nBits]   无符号位值 (nBits表示用多少位来存储这个值)

RECT 格式
Field       Type        Comment
Nbits       UB[5]       Bits used for each subsequentfield
Xmin        SB[Nbits]   x minimum position for rectangle in twips
Xmax        SB[Nbits]   x maximum position for rectangle in twips
Ymin        SB[Nbits]   y minimum position for rectangle in twips
Ymax        SB[Nbits]   y maximum position forrectangle in twips

第一个Nbits为5位长度的UB,这个值就是下面的[Nbits]值
这里就需要先写个函数,读取指定字节长度的值
注意:这里的单位都是twips 1px = 20twips
舞台的宽=Xmax-Xmin
舞台的高=Ymax-Ymin

/**
* 读取一定长度的位
* 无符号的
*
* @param bytes 二进制序列
* @param bitStartPosition 开始读取的位置,从0开始算
* @param bitLength     读取长度
* @return 无符号数字
*
*/    
public static function readUBits(bytes:ByteArray, bitStartPosition:int, bitLength:int):uint
{
    var bitBuffer:int;
    var bitCursor:int;
   
    var remainLength:int;
    var result:uint=0;
   
    bitCursor= bitStartPosition % 8;
    bytes.position = bitStartPosition / 8;
   
    if (bitCursor == 0)
    {
        bitBuffer = bytes.readUnsignedByte();
        bitCursor = 8;
    }else{
        bitBuffer = bytes.readUnsignedByte();
        bitBuffer = bitBuffer & (0xFF >> bitCursor);
        bitCursor = 8 - bitCursor;
    }
   
    while(bytes.bytesAvailable > 0)
    {
        remainLength = bitLength - bitCursor;
        if (remainLength > 0){
            result = result | (bitBuffer << remainLength);
            bitLength -= bitCursor;
            bitBuffer = bytes.readUnsignedByte();
            bitCursor = 8;
        }else{
            result = result | (bitBuffer >>-remainLength);
            return result;
        }
    }
   
    return 0;
}


/**
* 读取一定长度的位
* 有符号的
*
* @param bytes 二进制序列
* @param bitStartPosition 开始读取的位置,从0开始算
* @param bitLength 读取长度
* @return 有符号数字
*
*/    
public static function readSBits(bytes:ByteArray, bitStartPosition:int, bitLength:int):int{
   
    var result:int = readUBits(bytes, bitStartPosition, bitLength);
   
    var offset:int = (32 - bitLength);
    // 补齐符号位
    result = ((result << offset) >> offset);
   
    return result;
}


/**
* 读取rect结构
*
* @param bytes
* @param rect 如果传入,则使用该对象
* @return
*
*/    
public static function readRect(bytes:ByteArray, rect:Rect = null):Rect
{
    if (rect == null)
        rect = new Rect();
   
    var start:int = bytes.position* 8;
    var length:uint = readUBits(bytes, start, 5);
   
    rect.xMinTwips = readSBits(bytes, start + 5, length);
    rect.xMaxTwips = readSBits(bytes, start + 5 + length, length);
    rect.yMinTwips = readSBits(bytes, start + 5 + length * 2, length);
    rect.yMaxTwips = readSBits(bytes, start + 5 + length*3, length);
   
    return rect;
}


然后读取帧率
bytes.position++;// 帧率后8位有效,跳过1个字节(8位)
frameRate = bytes.readByte();

读取总帧数
totalFrames = bytes.readShort();


文件头就解析完成了

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐