我做了一个解压SWF文件的工具.
  但是有点问题.先把原理发来.让大家看看.我在本地建了一个SWF文件。用16进制编写器,分析了。看下面我的分析
我的swf文件的16进制编码如下:
43 57 53 07 76 00 00 00 78 9C AB 60 60 8D 67 60
E0 5F C0 C0 C0 C3 C8 E0 CC F4 FF .. .. .. .. ..
.....
.....(从FF开始到01为数据区,包括FF和01)
.....
.....
................................ 01 B7 D1 12 8A
==================================================================
下面以我的SWF文件结构为例,我们来解析一下。
43 57 53    // swf头文件信息 3字节 CWS为压缩格式,采用zlib压缩.. 
07          // swf版本号     1字节
38 01 00 00 // 文件长度      4字节  //  计算是反过来算低位在前前8个字节没有压缩,后面全是压缩的。下面的内容就是要解压的内容。78          // 影片宽高数据控制码. -> 控制码对应值看下表.
            // 这里的78对应下面550*400
9C AB 60 60 8D 67 60 E0 //影片的宽度与高度数据存放区
                        // 所占字节数由控制码决定
                        // 通过78查到的应该是:
                        //0 0 0 5 5 F 0 0 0 0 0 F A 0 0 0 被压缩了。
5F          // 一个字节,作用不详. 
C0          // 影片的放影速度  没压缩应该是 0C =12帧/秒。
C0 C0          // ,影片只有一帧. 计算是反过来算低位在前C3          // 作用不详.
C8          // 作用不详.E0          // 背景色中红色值 
CC          // 背景色中绿色值 
F4          // 背景色中蓝色值 FF...01     // 影片数据区 ++ (重点)B7 D1 12 8A // 文件结束符。正常是文件的最后四个字节为40 00 00 00 -----------------------------------------------------------------
下表中将控制码所在的字节分为两部分(高四位和低四位)。高低位不同的组合决定了数据区占用字节数以及不同的高度算法。  相应的控制码后的蓝色条表示数据区所占用的字节。五星代表有效数据(注意每个五星只占半个字节),其中前面几个连续的五星对应的数据记录了高度值,后面几个连续的五星 对应的数据记录了宽度值。  将连续的五星所在位置的数(十六进制)组合起来,得到四位或六位的十六进制数,将此数转换成十进制数,白色五星得到的数除以10就是影片宽度数值,红色五星得到的数除以40就是影片高度数值。  我对每一种控制码都给出一个具体例子,请对比文件中相应的字节和实际的宽度和高度值。控制码对应表 ( 一般就是这几种)
======================================================
控制码 0 1 2 3 4 5 6 7 8 宽×高 
50 ****   ****                   18×18 
0 0 B 4 0 0 0 B 4 0                 
58   ****   ****                 36×18 
0 0 5 A 0 0 0 0 B 4 0 0             
60   ****     ****               100×48 
0 0 3 E 8 0 0 0 1 E 0 0             
68     ****     ****             160×100 
0 0 1 9 0 0 0 0 0 3 E 8 0 0         
70     ****       ****           400×320 
0 0 0 F A 0 0 0 0 0 C 8 0 0         
78       ****       ****         550×400 
0 0 0 5 5 F 0 0 0 0 0 F A 0 0 0     
80       ****         ****       1600×1200 
0 0 0 3 E 8 0 0 0 0 0 2 E E 0 0     
88     ******        ****     2880×2880 
0 0 0 1 C 2 0 0 0 0 0 0 7 0 8 0 0 0

解决方案 »

  1.   

    现在来看我的代码:
    unit MainUnit;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, Buttons, ComCtrls,zLib;type
      TMainFrm = class(TForm)
        GroupBox1: TGroupBox;
        Label1: TLabel;
        swfPathET: TEdit;
        Label2: TLabel;
        SpeedButton1: TSpeedButton;
        iCode: TEdit;
        SpeedButton2: TSpeedButton;
        infoM: TMemo;
        SB: TStatusBar;
        OpenDialog: TOpenDialog;
        procedure SpeedButton1Click(Sender: TObject);
        procedure SpeedButton2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      MainFrm: TMainFrm;implementation
    Const
      selectSWF = '请选择文件!';
      inputmmcode = '请输插入代码!';
      NotSWFFile  = '选择的文件不是有效的SWF文件!';
    var
      fFlag : string;
      fversion : string;
      fLength,zipLength  : integer;{$R *.dfm}procedure Showmsg(msg : string);
    begin
      application.MessageBox(pchar(msg),'提示',mb_ok+mb_iconinformation); 
    end;Function unzipswf(swfStream : TMemoryStream;var unZipStream : TMemoryStream) : boolean;
    var
      fheard: array[0..7] of char;
      fbody : pchar;
      count : integer;
      SourceStream : TDecompressionStream;
      DestStream : TMemoryStream;
      procedure parseheard;
      begin
        fFlag := fheard[0]+fheard[1]+fheard[2];
        fversion := IntToStr(ord(fheard[3]));
        flength  := (ord(fheard[7]) * $ffffff) +(ord(fheard[6]) *$ffff)
                   +(ord(fheard[5])* $ff) +ord(fheard[4]);
        zipLength := flength -8 ; // 解压文件的长度.
      end;
    begin
       result := False;
       swfStream.Position := 0;
       swfStream.Read(fheard,sizeof(fheard));
       parseheard;
       if (fFlag <> 'FWS') and (fFlag <> 'CWS') then begin
         ShowMsg(NotSWFFile);
         exit;
       end;
       if fFlag = 'FWS' then unZipStream := swfStream;
       if fFlag = 'CWS' then begin    // 压缩的格式,现在解压.
         DestStream := TMemoryStream.Create;
         Try
           count := swfStream.Read(fbody,sizeof(fbody));
           while count > 0 do begin
             DestStream.Write(fbody,sizeof(fbody)); //读出从第9字节开始后的内容.进行解压.
             count := swfStream.Read(fbody,sizeof(fbody));
           end;
           
           destStream.SaveToFile('c:\abc.swf'); 
           destStream.Position := 0;       SourceStream := TDecompressionStream.Create(destStream);
           try
             count := SourceStream.Read(fbody,sizeof(fbody));
             unZipStream.Position := 0;
             while count > 0 do begin
               unZipStream.Write(fbody, count);
               count := SourceStream.Read(fbody,sizeof(fbody));
               //我总认为上面这句有问题.请大家帮我看看.
             end;
           finally
             SourceStream.Free;
           end;
         finally
           DestStream.Free;
         end;
       end; 
       result := true;
    end;procedure TMainFrm.SpeedButton1Click(Sender: TObject);
    begin
      if OpenDialog.Execute then
        swfpathET.Text := OpenDialog.FileName;
    end;procedure TMainFrm.SpeedButton2Click(Sender: TObject);
      function CheckUserInput : Boolean;
      begin
        result := false;
        if trim(swfpathet.Text) = '' then begin
          Showmsg(selectSWF);
          exit;
        end;
        if trim(icode.Text) = '' then begin
          showmsg(inputmmcode);
          exit;
        end;
        result := true;
      end;
    var
      swfStream : TMemoryStream;
      unzipStream : TMemoryStream;
    begin
      if CheckUserInput then begin
        swfStream := TMemorystream.Create;
        swfStream.LoadFromFile(swfpathet.text);
        unzipStream := TMemoryStream.Create;
        if unzipswf(swfStream,unZipStream) then
        unZipStream.SaveToFile('c:\px.swf');  // 这个是测试用的,生成解压的内容来看.
        unZipStream.Free;  
        swfStream.free;
      end;
    end;end.
    ////////////////////
    程序读取压缩长度是4的倍数是可以正常解压文件.
    但是其他的好像不行.会出现假死状态.
    请大家帮我解决下.
    谢谢....
      

  2.   

    //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
    //
    //      RestoreCompressed       转化压缩过的影片
    //
    //      sSwfName                影片文件名称
    //
    //      另外,本函数用到了两个外部变量: FileLength, FileBuf
    //            本函数改写了它们的值
    //
    //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
    function RestoreCompressed( sSwfName, sSaveName: String ): Boolean;
    var
      f,fw : File;
      fws : string[3];  //标示信息
      version : Byte;   //SWF文件版本号
      CurrentPos : Integer; //内存读写位置
      zStream : TDecompressionStream;      //实现压缩数据还原
      inStream : TMemoryStream;  //压缩数据流
    begin
      Result := FALSE;  FileMode := fmOpenRead;
      AssignFile( f, sSwfName );
      Reset( f,1 );
      SetLength( FileBuf, FileSize(f) );
      BlockRead( f,FileBuf[0], Filesize(f) ); //将文件读入内存
      CloseFile( f );  //下面为读取SWF文件的文件头Header部分
      CurrentPos:=0;
      //读取'FWS'标示
      SetLength(fws,3);
      Move( FileBuf[CurrentPos], fws[1], 3 );
      Inc( CurrentPos, 3 );
      if fws <> 'CWS' then
      begin
        SetLength( FileBuf,0 );
        ShowMessage('This SWF is not compressed.');
        exit;
      end;  //读取版本号
      Move( FileBuf[CurrentPos], version, Sizeof(version) );
      Inc( CurrentPos, Sizeof(version) );
      if Version < VERSION_ALLOW then
      begin
        SetLength(FileBuf,0);
        ShowMessage('This SWF version is not 5 or higher, can not be operated currently.');
        exit;
      end;
      //读取SWF文件长度
      Move( FileBuf[CurrentPos] ,FileLength,Sizeof(FileLength) );
      Inc( CurrentPos, Sizeof(FileLength) );
      //FileBuf下面的内容都是压缩数据
      inStream := TMemoryStream.Create;
      //将压缩数据读入inStream压缩数据流
      inStream.Write( FileBuf[CurrentPos], Length(FileBuf)-3-Sizeof(version)-Sizeof(FileLength) );
      inStream.Position := 0;
      //实现还原
      zStream:=TDecompressionStream.Create( inStream );
      //数据还原后所需缓冲区长度会加长
      SetLength(FileBuf,FileLength);
      //将还原的数据写会缓冲区
      zStream.Read( FileBuf[3+Sizeof(version)+Sizeof(FileLength)],
                    FileLength-3-Sizeof(version)-Sizeof(FileLength) );
      zStream.Free;
      inStream.Free;
      fws := 'FWS';
      //将原CWS改为FWS
      Move( fws[1], FileBuf[0],3 );  AssignFile( fw, sSaveName );
      ReWrite( fw,1 );
      BlockWrite( fw,FileBuf[0],Length(FileBuf) );
      CloseFile( fw );
      SetLength( FileBuf,0 );  Result := TRUE;
    end;const
      VERSION_ALLOW         = 5; // 可处理的最低影片版本
      

  3.   

    FileLength    : LongWord;      // SWF文件尺寸
      FileBuf       : Array of Byte; // 将SWF文件读入内存存放