跳到主内容

SWF 的三种压缩方式:FWS、CWS 与 ZWS

FWS、CWS、ZWS 是同一只 SWF 的三种外包装;从文件头看看 none、zlib 和 LZMA 是怎么回事。

Flash 保存计划 · 最近整理于 2026年7月30日

本文目录 · 6 节
  1. 先看最前面的 8 个字节
  2. FWS / none:没有整体压缩
  3. CWS / zlib:最常见的整体压缩
  4. ZWS / LZMA:更晚出现的高压缩率方式
  5. 能解压,不等于能播放
  6. 相关词条

拿到一只 SWF,最先值得看的不是画面,而是开头三个字节。它们会是 FWS、CWS 或 ZWS,分别表示不压缩、zlib 和 LZMA。可以把它们看成同一卷影片的三种外包装:拆开之后,舞台、帧、脚本和媒体资源仍是原来的内容。

这三个字节同时也是文件签名,解析器一见到它们,就知道接下来的主体该直接读,还是先解压。

文件签名 本馆显示 外层处理 规范版本下限
FWS46 57 53 none 不压缩 SWF 1
CWS43 57 53 zlib zlib 封装的 DEFLATE 数据流 SWF 6
ZWS5A 57 53 lzma SWF 专用封装的 LZMA1 数据流 SWF 13

先看最前面的 8 个字节

作品页上的 nonezliblzma 就是从文件签名翻译而来,和网站传输时的 Content-Encoding 无关,也不靠扩展名猜。

三种 SWF 都共用一段 8 字节的开头:

偏移  长度  含义
0     3     FWS / CWS / ZWS
3     1     SWF 版本(数值字节,不是字符)
4     4     FileLength(小端序,解压后的总长度)

FileLength 把这 8 个字节也算在内,写的是解压后的完整长度。所以 CWS、ZWS 的实际文件大小通常对不上这个数字;FWS 没有外层压缩,两者才应一致。

这件事在归档里不算小节。馆内的 SHA-256 是对原始文件逐字节计算的:同样的影片内容,一个存成 FWS,一个存成 CWS,哈希就会不同。我们会保留这层“包装”,因为它本来就是文件历史的一部分。

FWS / none:没有整体压缩

FWS 最直白。公共头之后就是影片主体:先读舞台矩形、帧率和帧数,然后一路进入 SWF Tag。

[ FWS ][版本][FileLength][舞台与帧信息][Tag][Tag]…
  3 B    1 B      4 B             未压缩主体

这种文件很适合检查和修复,因为不用先过一道解压。入库时,我们也会直接拿 FileLength 和实际大小核对;若对不上,常见原因是文件被截断、尾部多了东西,或文件头已经坏了。

FWS 通常更大,但也别把“通常”读成“必然”。文件很小,或里面大多是难以再次压缩的数据时,CWS、ZWS 加上自己的压缩头,未必能省下多少。

还有个容易看漏的地方:none 只说 SWF 整体没压缩。里面照样可以放 JPEG、MP3、压缩位图和视频。

CWS / zlib:最常见的整体压缩

CWS 是馆藏里很常见的一类。它保留前 8 个字节,从那里往后,把整段影片主体装进一个 zlib 数据流。zlib 内部使用 DEFLATE,另外带着自己的头和校验信息。

[ CWS ][版本][解压后 FileLength][ zlib(舞台与帧信息 + 全部 Tag) ]
  3 B    1 B          4 B                   压缩主体

ZIP、gzip、zlib、DEFLATE 这些名字很容易搅在一起。它们可能共享压缩算法,但并不是同一种封装;CWS 要的是 zlib。直接把主体丢给只认识 gzip 或裸 DEFLATE 的工具,往往打不开。

按 Adobe 的说法,CWS 从 SWF 6 起使用,Animate 也把 Deflate 对应到 Flash Player 6.x 及以后。不过老档案并不总照着手册来:偶尔会遇到版本字节低于 6、zlib 主体却好好的文件。只要结构和解压结果经得起检查,本馆仍会收下,同时原样展示它的低版本号。Ruffle 也会先提醒一句,再继续尝试解压。

ZWS / LZMA:更晚出现的高压缩率方式

ZWS 来得更晚,使用 LZMA1。它从 SWF 13 起出现,对应的运行环境则是 Flash Player 11.x 或 AIR 3.x 及以后。这里两个数字没写错:SWF 格式号和 Player 产品版本本来就不是一套编号。

Adobe 当年宣传 LZMA 时,提到它最高可比 Deflate 高效约 40%,尤其适合 ActionScript 或矢量图形较多的作品。这个“最高”很关键:碰上小文件,或 JPEG、MP3 这类已经压过的内容,收益可能很有限,解码倒会多花一些计算和内存。

ZWS 也不是普通 .xz 文件。公共头之后还有一套 SWF 专用布局:

[ ZWS ][版本][解压后长度][压缩长度][LZMA 属性 + 字典大小][LZMA1 数据]
  3 B    1 B      4 B        4 B              5 B          …

Ruffle 会把这套布局整理成解码库认识的 LZMA 参数,再用 FileLength - 8 确定主体长度。本馆的提取器也会重建 LZMA1 “alone” 头,并检查版本、扩展头、压缩长度、字典大小和最终输出。压缩文件有时很小,展开却可能大得惊人;这些检查既是在找损坏,也是在给解压过程设护栏。

能解压,不等于能播放

压缩方式解决的只是第一步:怎样把 SWF 主体拿出来。接下来还有 Tag、ActionScript、字体、音频和视频编码,每一层都可能影响播放。

Ruffle 现在三种格式都能读,所以看到 lzma 不必先判它“播不了”。真有问题,再往脚本、API、媒体编码或文件完整性查。倒是一些年代较早的播放器和反编译器只认识 FWS、CWS,见到 ZWS 会停在门口。

把 ZWS 转成 FWS 或 CWS,确实能帮这些旧工具一把。但转换会改变文件字节、大小和 SHA-256。馆藏里应留下原件,转换后的文件另算一份派生副本。

三种外层之间的转换本身是无损的,不会让画面或声音变糊。真正的损失来自 JPEG、MP3、视频等资源编码。作品页上的“文件大小”则是手里这份原件的字节数,不要和文件头里那个解压后的 FileLength 混成一个数字。

相关词条

这些资料从哪来

  1. Adobe SWF File Format Specification, Version 19
  2. Adobe Animate:Specify publish settings
  3. Ruffle:SWF reader and decompression implementation
  4. IETF RFC 1950:ZLIB Compressed Data Format
  5. IETF RFC 1951:DEFLATE Compressed Data Format
  6. 7-Zip:LZMA SDK