#!/usr/bin/perl -w =begin cws2fws v 0.0.1 - Flash format 6+ decompressor Jose Melo de Assis Fonseca / JMAF http://zefonseca.com/ 2008-04-26 Usage: cws2fws Will output a FWS uncompressed Flash file in same format and version to "COMPRESSED_SWF_FILE.fws.swf" This is free software which you can use, modify and redistribute in the same terms as Perl itself. Observing the SWF file format: - the first 3 bytes are a signature indicating file type - compressed files which SWF::Search currently cannot open always are CWS - files it opens fine are always FWS (SWF backwards?) - the next byte seems to match the version from output of the `file example.swf` command - according to http://the-labs.com/MacromediaFlash/SWF-Spec/SWFfileformat.html the next 4 bytes indicate the total file length. it is a little endian 32 bit integer. the url above mentions the file format is always "FWS", which is no longer true for versions 6 and above of the SWF file format. So how do we decompress the file? Seems to be simpler than I imagined. 1) read the 3 first bytes, compare to CWS, if not equal then exit 2) read the rest of the header. unless you need version or file length just leave version . length concatenated. we won't need them. 3) decompress everything from byte 9 to EOF 4) concatenate "FWS", the 5 header bytes and the decompressed stream =cut use Compress::Zlib qw{uncompress}; my $zlib_data; my $header; my $type_sig; my $unc; my $file_prefix; my $outfile; usage() unless(defined($ARGV[0])); if ( $ARGV[0] !~ m{^(.+?)\.swf}i) { usage(); } $file_prefix = $1; open(FIL, $ARGV[0]) or die "Fatal: Could not open source SWF file $ARGV[0]\n"; read(FIL, $type_sig, 3, 0); # is case sensitive, bytes must match ASCII 0x43 0x57 0x53 ("CWS" ) if ($type_sig eq 'FWS') { die "Flash file is not compressed(CWS) or header is invalid.\n"; } # reads last bytes of header read(FIL, $header, 5, 0); # filehandle pointer now at 8 bytes offset # the rest of the file is zlib compressed data while () { $zlib_data .= $_; } close(FIL); =begin i observed that the CWS file length(bytes 5 to 8, little endian 32 bit integer) does not match that of the compressed data. by decompressing and checking again i see that the length header field refers to the zlib uncompressed stream + 8 bytes (header length). therefore to finish our decompression all we have to do is substitute the first 3 byte signature for FWS and concatenate the rest of the header. works a dandy. - JMAF =cut $unc = uncompress($zlib_data); $outfile = $file_prefix . ".fws.swf"; open(ZIL, ">$outfile") or die "Fatal: Could not open target SWF file $outfile\n"; print ZIL "FWS" . $header . $unc; close(ZIL); sub usage { die "Usage: cws2fws COMPRESSED_SWF_FILE\n"; }