这里是使用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();
文件头就解析完成了
所有评论(0)