home *** CD-ROM | disk | FTP | other *** search
/ ftp.rarlab.com / 2014.05.ftp.rarlab.com.tar / ftp.rarlab.com / rar / RARComponent_12.zip / RAR.pas < prev    next >
Pascal/Delphi Source File  |  2009-02-03  |  27KB  |  753 lines

  1. //  written by Philippe Wechsler 2008
  2. //
  3. //  web: www.PhilippeWechsler.ch
  4. //  mail: contact@PhilippeWechsler.ch
  5. //
  6. //  please see license.txt and documentation.txt
  7. //
  8. //  changes in 1.2 stable
  9. //   - support for delphi 2009
  10. //   - support for unicode filenames (see TRARFileItem.FileNameW)
  11. //   - dll name + path is custom
  12. //   - fixed a memory leak (thanks to Claes EnskΣr)
  13. //   - some small improvements in the demo
  14. //  changes in 1.1 stable
  15. //   - fixed problem with mySelf pointer - you can use now multiple TRAR instances
  16. //   - "SFX" in archive informations
  17. //   - code better commented
  18. //   - bugfixing in reading multivolumes
  19. //
  20. //  known bugs:
  21. //   - when extracting files that contains unicode characters there's no test if
  22. //     the file exists allready
  23. //   - open archives that contains unicode characters in the archive name fails
  24.  
  25. unit RAR;
  26.  
  27. interface
  28.  
  29. uses
  30.   Classes, SysUtils,Windows,RAR_DLL;
  31.  
  32. type
  33.   TRAROperation=(roInitArchive, roListFiles, roExtract, roTest);
  34.  
  35. type
  36.   TRARProgressInfo = record
  37.     FileBytesDone:LongInt;
  38.     FileBytesTotal:LongInt;
  39.     FileName:WideString;
  40.     TotalSize:LongInt;
  41.   end;
  42.  
  43. type
  44.   TRARFileItem = record
  45.     FileName:AnsiString;
  46.     FileNameW:WideString;
  47.     CompressedSize:cardinal;
  48.     UnCompressedSize:cardinal;
  49.     HostOS:String;
  50.     CRC32:String;
  51.     Attributes:Cardinal;
  52.     Comment:AnsiString;
  53.     Time:tDateTime;
  54.     CompressionStrength:cardinal;
  55.     ArchiverVersion:cardinal;
  56.     Encrypted:boolean;
  57.   end;
  58.  
  59. type TRARReplaceData=record
  60.   FileName:AnsiString;
  61.   Size:int64;
  62.   Time:tDateTime;
  63. end;
  64.  
  65. TRARReplace=(rrCancel, rrOverwrite, rrSkip);
  66.  
  67. type
  68.   TOnRARErrorNotifyEvent = procedure(Sender: TObject; const ErrorCode:integer; const Operation: TRAROperation) of object;
  69.   TOnRARListFile = procedure(Sender: TObject; const FileInformation:TRARFileItem) of Object;
  70.   TOnRARPasswordRequired = procedure(Sender: TObject; const HeaderPassword:boolean; const FileName:AnsiString;out NewPassword:AnsiString; out Cancel:boolean) of object;
  71.   TOnRARNextVolumeRequired = procedure(Sender: TObject;const requiredFileName:AnsiString; out newFileName:AnsiString ;out Cancel:boolean) of Object;
  72.   TOnRARProcess = procedure(Sender: TObject; const FileName:WideString; const ArchiveBytesTotal, ArchiveBytesDone, FileBytesTotal, FileBytesDone:cardinal) of Object;
  73.   TOnRARReplace = procedure(Sender: TObject; const ExistingData,NewData:TRARReplaceData;out Action:TRARReplace) of object;
  74.  
  75. type
  76.   TRARArchiveInformation = class (TPersistent)
  77.   private
  78.     fOpened:boolean;
  79.     fFileName:AnsiString;
  80.     fArchiverMajorVersion:Cardinal;
  81.     fArchiverMinorVersion:Cardinal;
  82.     fDictionarySize:int64;
  83.     fEncryption:boolean;
  84.     fSolid:boolean;
  85.     fHostOS:String;
  86.     fTotalFiles:integer;
  87.     fCompressedSize:int64;
  88.     fUnCompressedSize:int64;
  89.     fHeaderEncrypted:boolean;
  90.     fMultiVolume:boolean;
  91.     fArchiveComment:boolean;
  92.     fFileComment:boolean;
  93.     fComment:AnsiString;
  94.     fSigned:boolean;
  95.     fLocked:boolean;
  96.     fRecovery:boolean;
  97.     fSFX:boolean;
  98.     procedure Reset;
  99.   protected
  100.   public
  101.   published
  102.     property FileName: AnsiString read fFileName;
  103.     property ArchiverMajorVersion: cardinal read fArchiverMajorVersion;
  104.     property ArchiverMinorVersion: cardinal read fArchiverMinorVersion;
  105.     property DictionarySize: int64 read fDictionarySize;
  106.     property Encryption: boolean read fEncryption;
  107.     property Solid: boolean read fSolid;
  108.     property HostOS: String read fHostOS;
  109.     property TotalFiles: integer read fTotalFiles;
  110.     property CompressedSize: int64 read fCompressedSize;
  111.     property UnCompressedSize: int64 read fUnCompressedSize;
  112.     property HeaderEncrypted: boolean read fHeaderEncrypted;
  113.     property MultiVolume: boolean read fMultiVolume;
  114.     property ArchiveComment: boolean read fArchiveComment;
  115.     property FileComment: boolean read fFileComment;
  116.     property Comment: AnsiString read fComment;
  117.     property Signed: boolean read fSigned;
  118.     property Locked: boolean read fLocked;
  119.     property Recovery: boolean read fRecovery;
  120.     property SFX: boolean read fSFX;
  121.   end;
  122.  
  123. type
  124.   TRAR = class(TComponent)
  125.   private
  126.     RARDLLInstance:THandle;
  127.     fAbort:Boolean;
  128.     fProgressInfo:TRARProgressInfo;
  129.     fReadMVToEnd:boolean;
  130.     fPackedSizeMVVolume:Cardinal;
  131.     Password:AnsiString;
  132.     Comment:PAnsiChar;
  133.     CommentResult:Cardinal;
  134.     fArchiveInformation:TRARArchiveInformation;
  135.     ArchiveData:TRARArchiveDataEx;
  136.     ArchiveHandle:Cardinal;
  137.     hdrData:TRARHeaderDataEx; 
  138.     //hdrData:TRARHeaderData;
  139.     fDLLName:AnsiString;
  140.     fOnError:TOnRARErrorNotifyEvent;
  141.     fOnListFile:TOnRARListFile;
  142.     fOnPasswordRequired:TOnRARPasswordRequired;
  143.     fOnNextVolumeRequired:TOnRARNextVolumeRequired;
  144.     fOnProcess:TOnRARProcess;
  145.     fOnReplace:TOnRARReplace;
  146.     MySelf: Pointer;
  147.     function InitArchive(Extract:boolean):boolean;
  148.     function CloseArchive:boolean;
  149.     function OnUnRarCallBack(msg:Cardinal; UserData, P1, P2:LongInt):integer; stdcall;
  150.     procedure ProgressHeader;
  151.     procedure Error(ErrorCode:integer;Operation:TRAROperation);
  152.     function getVersion:String;
  153.   protected
  154.   public
  155.     constructor Create(AOwner: TComponent); override;
  156.     destructor Destroy; override;
  157.  
  158.     function OpenFile(FileName:String):boolean;
  159.     function List:boolean;
  160.     function Extract(Path:AnsiString;RestoreFolder:Boolean;Files:TStrings):boolean;
  161.     function Test:boolean;
  162.     procedure Abort;
  163.     procedure LoadDLL;
  164.     procedure UnloadDLL;
  165.     function isDLLLoaded:boolean;
  166.     function GetDllVersion:integer;
  167.   published
  168.     property Version: String read getVersion;
  169.     property ReadMultiVolumeToEnd:boolean read fReadMVToEnd write fReadMVToEnd; //if true, mv's will be read until last part of the file
  170.     //pro:display correct crc + display all files in all parts
  171.     //contra: all volumes required=to open you have to insert all disk if not all volumes in sam folder
  172.     property DllName: AnsiString read fDLLName write fDLLName;
  173.     property OnError: TOnRARErrorNotifyEvent read fOnError write fOnError;
  174.     property OnListFile: TOnRARListFile read fOnListFile write fOnListFile;
  175.     property OnPasswordRequired: TOnRARPasswordRequired read fOnPasswordRequired write fOnPasswordRequired;
  176.     property OnNextVolumeRequired:TOnRARNextVolumeRequired read fOnNextVolumeRequired write fOnNextVolumeRequired;
  177.     property OnProgress: TOnRARProcess read fOnProcess write fOnProcess;
  178.     property OnReplace: TOnRARReplace read fOnReplace write fOnReplace;
  179.     property ArchiveInformation:TRARArchiveInformation read fArchiveInformation;
  180.   end;
  181.  
  182. procedure Register;
  183.  
  184. implementation
  185.  
  186. const
  187.   fVersion='1.2';
  188.  
  189. procedure Register;
  190. begin
  191.   RegisterComponents('Philippe Wechsler', [TRAR]);
  192. end;
  193.  
  194. function UnRarCallBack(msg:Cardinal; UserData, P1, P2:LongInt):integer; stdcall;
  195. begin
  196.   //Result:=TRAR(mySelf).OnUnRarCallBack(msg, UserData, P1, P2);
  197.   Result:=TRAR(UserData).OnUnRarCallBack(msg, UserData, P1, P2);
  198. end;
  199.  
  200. function TRAR.OnUnRarCallBack(msg:Cardinal; UserData, P1, P2:LongInt):integer; stdcall;
  201. var
  202.   Password, FileName, PasswordFile:AnsiString;
  203.   Cancel:Boolean;
  204. begin
  205.   Password:='';
  206.   Cancel:=False;
  207.   Result:=0;
  208.   case msg of
  209.     UCM_CHANGEVOLUME: begin
  210.                         FileName:=PAnsiChar(P1);
  211.                         case P2 of
  212.                           RAR_VOL_ASK:    begin
  213.                                             if (not fArchiveInformation.fOpened) and (not fReadMVToEnd) then begin
  214.                                               Result:=-1
  215.                                             end else begin
  216.                                               if assigned(fOnNextVolumeRequired) then
  217.                                                 fOnNextVolumeRequired(Self,PAnsiChar(P1),FileName,Cancel);
  218.                                               StrPCopy(PAnsiChar(P1),FileName); //todo: handle error if P1 has not enough space for FileName
  219.                                               if fAbort or Cancel then
  220.                                                 Result:=-1
  221.                                               else
  222.                                                 Result:=0;
  223.                                             end;
  224.                                           end;
  225.                           RAR_VOL_NOTIFY: begin        //occurs when next volume required and next part was found
  226.                                             Result:=0; //continue
  227.                                           end;
  228.                         end;
  229.  
  230.                       end;
  231.     UCM_NEEDPASSWORD: begin
  232.                         if not fArchiveInformation.fOpened then begin
  233.                           fArchiveInformation.fHeaderEncrypted:=True;
  234.                           PasswordFile:=fArchiveInformation.FileName;
  235.                         end else
  236.                           PasswordFile:=fProgressInfo.FileName;
  237.                         if assigned(fOnPasswordRequired) then
  238.                           fOnPasswordRequired(Self,not fArchiveInformation.fOpened,PasswordFile,Password,Cancel);
  239.                         StrPCopy(Pointer(P1), Copy(Password, 1, P2));
  240.                         if fAbort or Cancel then
  241.                           Result := -1
  242.                         else
  243.                           Result := 0;
  244.                       end;
  245.     UCM_PROCESSDATA:  begin
  246.                         fProgressInfo.FileBytesDone:=fProgressInfo.FileBytesDone+P2;
  247.                         fProgressInfo.TotalSize:=fProgressInfo.TotalSize+P2;
  248.                         if assigned(fOnProcess) then
  249.                           fOnProcess(Self,fProgressInfo.FileName,
  250.                           fArchiveInformation.UnCompressedSize, fProgressInfo.TotalSize,
  251.                           fProgressInfo.FileBytesTotal,fProgressInfo.FileBytesDone);
  252.                         if fAbort then
  253.                           Result := -1
  254.                         else
  255.                           Result := 0;
  256.                       end;
  257.   end;
  258.   if fAbort then
  259.     Result:=-1;
  260. end;
  261.  
  262. constructor TRAR.Create(AOwner: TComponent);
  263. begin
  264.   inherited Create(AOwner);
  265.   fArchiveInformation:=TRARArchiveInformation.Create;
  266.   fReadMVToEnd:=False;
  267.   mySelf:=Self;
  268.   fDLLName:='unrar.dll';
  269. end;
  270.  
  271. destructor TRAR.Destroy;
  272. begin
  273.   if Assigned(comment) then
  274.     FreeMem(comment);
  275.   FreeAndNil(fArchiveInformation);
  276.   UnLoadDLL;
  277.   inherited Destroy;
  278. end;
  279.  
  280. function TRAR.OpenFile(FileName: string):boolean;
  281. begin
  282.   fArchiveInformation.Reset;
  283.   if not isDLLLoaded then
  284.     LoadDLL;
  285.   if not isDLLLoaded then begin
  286.     Error(ERAR_DLL_LOAD_ERROR,roInitArchive);
  287.     Result:=False;
  288.     Exit;
  289.   end;
  290.   fArchiveInformation.fFileName:=FileName;
  291.   Result:=List;
  292.   fArchiveInformation.fOpened:=True;
  293. end;
  294.  
  295. function TRAR.InitArchive(Extract:boolean):boolean;
  296. begin
  297.   Result:=True;
  298.   CommentResult:=RAR_SUCCESS;
  299.   with ArchiveData do begin
  300.     OpenResult:=RAR_SUCCESS;
  301.     if Extract then
  302.       OpenMode:=RAR_OM_EXTRACT
  303.     else
  304.       if fReadMVToEnd then
  305.         OpenMode:=RAR_OM_LIST_INCSPLIT
  306.       else
  307.         OpenMode:=RAR_OM_LIST;
  308.     ArcName:=PAnsiChar(fArchiveInformation.FileName);
  309.     //ArcNameW:=PWideChar(fArchiveInformation.FileName);
  310.     if not Assigned(Comment) then
  311.       GetMem(Comment,MAX_RAR_COMMENTSIZE);
  312.     CmtBuf:=Comment;
  313.     CmtBufSize:=MAX_RAR_COMMENTSIZE;
  314.     CmtSize:=length(Comment);
  315.     CmtState:=CommentResult;
  316.   end;
  317.   ArchiveHandle:=RAROpenArchiveEx(@ArchiveData);
  318.   //ArchiveHandle:=RAROpenArchive(@ArchiveData);
  319.   if ArchiveHandle=0 then begin           //handle incorrect=failed to load dll
  320.     Error(ERAR_DLL_LOAD_ERROR,roInitArchive);
  321.     Result:=False;
  322.     exit;
  323.   end;
  324.   //((ArchiveData.Flags and $00000100)=$00000100)=first volume
  325.   //((ArchiveData.Flags and $00000001)=$00000001)=Volume attribute (archive volume)
  326.   //((ArchiveData.Flags and $00000010)=$00000010)=New volume naming scheme ('volname.partN.rar')
  327.  
  328.   if ((ArchiveData.Flags and $00000004)=$00000004) then    //set archive info
  329.     fArchiveInformation.fLocked:=True;
  330.   if ((ArchiveData.Flags and $00000020)=$00000020) then
  331.     fArchiveInformation.fSigned:=True;
  332.   if ((ArchiveData.Flags and $00000040)=$00000040) then
  333.     fArchiveInformation.fRecovery:=True;
  334.   if ((ArchiveData.Flags and $00000008)=$00000008) then
  335.     fArchiveInformation.fSolid:=True;
  336.   if ((ArchiveData.Flags and $00000002)=$00000002) then
  337.     fArchiveInformation.fArchiveComment:=True;
  338.   if ((ArchiveData.Flags and $00000080)=$00000080) then
  339.     fArchiveInformation.fHeaderEncrypted:=True;
  340.   fArchiveInformation.fSFX:=isSFX(fArchiveInformation.FileName);
  341.  
  342.   case ArchiveData.CmtState of                              //read archive comment
  343.     ERAR_COMMENTS_EXISTS: begin
  344.                             fArchiveInformation.fComment:=StrPas(Comment);
  345.                             fArchiveInformation.fArchiveComment:=True;
  346.                           end;
  347.     ERAR_NO_COMMENTS:     begin
  348.                             fArchiveInformation.fComment:='';
  349.                             fArchiveInformation.fArchiveComment:=False;
  350.                           end;
  351.     ERAR_NO_MEMORY:       Error(ERAR_NO_MEMORY,roInitArchive);
  352.     ERAR_BAD_DATA:        Error(ERAR_BAD_DATA,roInitArchive);
  353.     ERAR_UNKNOWN_FORMAT:  Error(ERAR_UNKNOWN_FORMAT,roInitArchive);
  354.     ERAR_SMALL_BUF:       Error(ERAR_SMALL_BUF,roInitArchive);
  355.   end;
  356.   if (ArchiveData.CmtState<>ERAR_NO_COMMENTS) and (ArchiveData.CmtState<>ERAR_COMMENTS_EXISTS) then
  357.     result:=False;      //error reading comment
  358. end;
  359.  
  360. function TRAR.CloseArchive:boolean;
  361. var
  362.   CloseResult:integer;
  363. begin
  364.   CloseResult:=RARCloseArchive(ArchiveHandle);
  365.   if CloseResult=ERAR_ECLOSE then
  366.     Error(ERAR_ECLOSE,roInitArchive);
  367.   Result:=(CloseResult=RAR_SUCCESS);
  368. end;
  369.  
  370. procedure TRAR.ProgressHeader;     //write data to archiv information and  list file
  371. var
  372.   FileItem:TRARFileItem;
  373.   ft: _FILETIME;
  374.   st: TSystemTime;
  375.   OS:String;
  376. begin
  377.   if (fReadMVToEnd) and (not ((hdrData.Flags and $00000001)=$00000001)) and  //first part of the file
  378.     (((hdrData.Flags and $00000002)=$00000002)) then
  379.     fPackedSizeMVVolume:=hdrData.PackSize;
  380.   if (fReadMVToEnd) and (((hdrData.Flags and $00000001)=$00000001)) and  //not last, not first part
  381.     (((hdrData.Flags and $00000002)=$00000002)) then begin
  382.     fPackedSizeMVVolume:=fPackedSizeMVVolume+hdrData.PackSize;
  383.     exit;
  384.   end;
  385.   if (fReadMVToEnd) and (((hdrData.Flags and $00000001)=$00000001)) and  //last part
  386.     (not ((hdrData.Flags and $00000002)=$00000002)) then
  387.     hdrData.PackSize:=hdrData.PackSize+fPackedSizeMVVolume;
  388.  
  389.   if (fReadMVToEnd) and ((hdrData.Flags and $00000002)=$00000002) then //not last part
  390.     exit;
  391.  
  392.   if fArchiveInformation.fArchiverMajorVersion*10+fArchiveInformation.fArchiverMinorVersion<hdrData.UnpVer then begin
  393.     fArchiveInformation.fArchiverMinorVersion:=hdrData.UnpVer mod 10;
  394.     fArchiveInformation.fArchiverMajorVersion:=(hdrData.UnpVer-fArchiveInformation.fArchiverMinorVersion) div 10;
  395.   end;
  396.   if ((hdrData.Flags and $00000004)=$00000004) then
  397.     fArchiveInformation.fEncryption:=True;
  398.   if ((hdrData.Flags and $00000010)=$00000010) then
  399.     fArchiveInformation.fSolid:=True;
  400.   OS:='unknown';
  401.   case hdrData.HostOS of
  402.     0: OS:='DOS';
  403.     1: OS:='IBM OS/2';
  404.     2: OS:='Windows';
  405.     3: OS:='Unix';
  406.   end;
  407.   fArchiveInformation.fHostOS:=OS;
  408.   if (not ((hdrData.Flags and $00000070)=$00000070)) and (hdrData.FileAttr<>faDirectory) then begin//not a directory
  409.     fArchiveInformation.fTotalFiles:=fArchiveInformation.fTotalFiles+1;
  410.     case (hdrData.Flags shl 24 shr 29) of
  411.       0: fArchiveInformation.fDictionarySize:=65536;
  412.       1: fArchiveInformation.fDictionarySize:=131072;
  413.       2: fArchiveInformation.fDictionarySize:=262144;
  414.       3: fArchiveInformation.fDictionarySize:=524288;
  415.       4: fArchiveInformation.fDictionarySize:=1048576;
  416.       5: fArchiveInformation.fDictionarySize:=2097152;
  417.       6: fArchiveInformation.fDictionarySize:=4194304;
  418.     end;
  419.   end;
  420.   fArchiveInformation.fCompressedSize:=fArchiveInformation.fCompressedSize+hdrData.PackSize;
  421.   fArchiveInformation.fUnCompressedSize:=fArchiveInformation.fUnCompressedSize+hdrData.UnpSize;
  422.   if ((hdrData.Flags and $00000001)=$00000001) or ((hdrData.Flags and $00000002)=$00000002) then    //file continued in last or next part
  423.     fArchiveInformation.fMultiVolume:=True;
  424.   if hdrData.CmtSize>0 then
  425.     fArchiveInformation.fFileComment:=True;
  426.   
  427.   with FileItem do begin
  428.     FileName:=StrPas(hdrData.FileName);
  429.     FileNameW:=hdrData.FileNameW;
  430.     CompressedSize:=hdrData.PackSize;
  431.     UnCompressedSize:=hdrData.UnpSize;
  432.     HostOS:=OS;
  433.     CRC32:=Format('%x',[hdrData.FileCRC]);
  434.     Attributes:=hdrData.FileAttr;
  435.     Comment:=hdrData.CmtBuf;
  436.     DosDateTimeToFileTime(HiWord(hdrData.FileTime),
  437.       LoWord(hdrData.FileTime),
  438.       ft);
  439.     FileTimeToSystemTime(ft,st);
  440.     Time:=SystemTimeToDateTime(st);
  441.     CompressionStrength:=hdrData.Method;
  442.     ArchiverVersion:=hdrData.UnpVer;
  443.     Encrypted:=((hdrData.Flags and $00000004)=$00000004);
  444.   end;
  445.   if assigned(fOnListFile) then
  446.     fOnListFile(Self,FileItem);
  447. end;
  448.  
  449. procedure TRARArchiveInformation.Reset;
  450. begin
  451.   fOpened:=False;
  452.  
  453.   fFileName:='';
  454.   fTotalFiles:=0;
  455.   fArchiverMajorVersion:=0;
  456.   fArchiverMinorVersion:=0;
  457.   fDictionarySize:=0;
  458.   fEncryption:=False;
  459.   fSolid:=False;
  460.   fHostOS:='';
  461.   fTotalFiles:=0;
  462.   fCompressedSize:=0;
  463.   fUnCompressedSize:=0;
  464.   fHeaderEncrypted:=False;
  465.   fMultiVolume:=False;
  466.   fArchiveComment:=False;
  467.   fFileComment:=False;
  468.   fComment:='';
  469.   fLocked:=False;
  470.   fSigned:=False;
  471.   fRecovery:=False;
  472.   fSFX:=False;
  473. end;
  474.  
  475. function TRAR.List:boolean;
  476. var
  477.   ReadFileHeaderResult: integer;
  478. begin
  479.   assert(FileExists(fArchiveInformation.FileName));
  480.   fAbort:=False;
  481.   Result:=InitArchive(False);
  482.   if fAbort or (not Result) then exit;
  483.   try
  484.     mySelf:=Self;
  485.     RARSetCallback(Archivehandle,UnRarCallBack,Integer(mySelf));
  486.     if Password<>'' then
  487.       RARSetPassword(ArchiveHandle,PAnsiChar(Password));
  488.     readFileHeaderResult:=RAR_SUCCESS;
  489.     while (ReadFileHeaderResult=RAR_SUCCESS) and Result do begin
  490.       ReadFileHeaderResult:=RARReadHeaderEx(ArchiveHandle,@hdrData);
  491.       //ReadFileHeaderResult:=RARReadHeader(ArchiveHandle,@hdrData);
  492.  
  493.       if ReadFileHeaderResult=ERAR_END_ARCHIVE then
  494.         break;
  495.       if ReadFileHeaderResult<>RAR_SUCCESS then
  496.         Result:=False;
  497.       Error(ReadFileHeaderResult,roListFiles);
  498.  
  499.       ProgressHeader; //fOnListFile + writte data to farchiveInformation
  500.       ReadFileHeaderResult:=RARProcessFile(ArchiveHandle,RAR_SKIP,NIL,NIL);
  501.  
  502.       if ReadFileHeaderResult<>RAR_SUCCESS then
  503.         Result:=False;
  504.       Error(ReadFileHeaderResult,roListFiles);
  505.     end;
  506.   finally
  507.     CloseArchive;
  508.   end;
  509. end;
  510.  
  511. function extractFile(FileName:String;Files:TStrings):boolean;   //returns if the actual file should be extracted or not
  512. var
  513.   i:integer;
  514. begin
  515.   if Files=NIL then
  516.     Result:=True
  517.   else
  518.     begin
  519.       Result:=False;
  520.       for i := 0 to Files.Count - 1 do          //check if actual file is in the filelist
  521.         if Files[i]=FileName then begin
  522.           Result:=True;
  523.           break;
  524.         end;
  525.     end;
  526. end;
  527.  
  528. function TRAR.Extract(Path:AnsiString;RestoreFolder:boolean;Files:TStrings):boolean;
  529. var
  530.   ReadFileHeaderResult: integer;
  531.   ExistentFile,ArchiveFile:TRARReplaceData;
  532.   ft: _FILETIME;
  533.   st: TSystemTime;
  534.   ReplaceResult: TRARReplace;
  535. begin
  536.   assert(FileExists(fArchiveInformation.FileName));
  537.   fAbort:=False;
  538.   Result:=InitArchive(True);
  539.   if fAbort or not (Result) then
  540.     exit;
  541.   if Path[Length(Path)]<>'\' then
  542.     Path:=Path+'\';
  543.   try
  544.     mySelf:=Self;
  545.     RARSetCallback(Archivehandle,UnRarCallBack,Integer(mySelf));
  546.     if Password<>'' then
  547.       RARSetPassword(ArchiveHandle,PAnsiChar(Password));
  548.     readFileHeaderResult:=RAR_SUCCESS;
  549.     fProgressInfo.TotalSize:=0;
  550.     while (ReadFileHeaderResult=RAR_SUCCESS) and Result do begin
  551.       ReadFileHeaderResult:=RARReadHeaderEx(ArchiveHandle,@hdrData);
  552.       //ReadFileHeaderResult:=RARReadHeader(ArchiveHandle,@hdrData);
  553.  
  554.       if ReadFileHeaderResult=ERAR_END_ARCHIVE then
  555.         Break;
  556.  
  557.       if ReadFileHeaderResult<>RAR_SUCCESS then begin
  558.         Result:=False;
  559.         Error(ReadFileHeaderResult,roListFiles);
  560.       end;
  561.  
  562.       fProgressInfo.FileBytesDone:=0;
  563.       fProgressinfo.FileBytesTotal:=hdrData.UnpSize;
  564.       fProgressInfo.FileName:=hdrData.FileNameW;
  565.       ReplaceResult:=rrOverWrite;
  566.  
  567.       if extractFile(StrPas(hdrData.FileName),Files) then begin    //todo: UniCode FileName
  568.  
  569.         if RestoreFolder then
  570.           ExistentFile.FileName:=Path+StrPas(hdrData.FileName)
  571.         else
  572.           ExistentFile.FileName:=Path+ExtractFileName(StrPas(hdrData.FileName));
  573.         ExistentFile.Size:=GetFileSize(ExistentFile.FileName);
  574.         ExistentFile.Time:=GetFileModifyDate(ExistentFile.FileName);
  575.         if RestoreFolder then
  576.           ArchiveFile.FileName:=StrPas(hdrData.FileName)
  577.         else
  578.           ArchiveFile.FileName:=ExtractFileName(StrPas(hdrData.FileName));
  579.         ArchiveFile.Size:=hdrData.UnpSize;
  580.         DosDateTimeToFileTime(HiWord(hdrData.FileTime),
  581.         LoWord(hdrData.FileTime),
  582.         ft);
  583.         FileTimeToSystemTime(ft,st);
  584.         ArchiveFile.Time:=SystemTimeToDateTime(st);
  585.  
  586.         if FileExists(ExistentFile.FileName) then
  587.           if assigned(fOnReplace) then
  588.             fOnReplace(Self,ExistentFile,ArchiveFile,ReplaceResult);
  589.  
  590.         case ReplaceResult of
  591.           rrCancel: fAbort:=True;
  592.           rrOverwrite: if RestoreFolder then
  593.                         ReadFileHeaderResult:=RARProcessFile(ArchiveHandle, RAR_EXTRACT, PAnsiChar(Path), NIL)
  594.                       else
  595.                         if (not ((hdrData.Flags and $00000070)=$00000070)) and (hdrData.FileAttr<>faDirectory) then
  596.                           ReadFileHeaderResult:=RARProcessFile(ArchiveHandle, RAR_EXTRACT, Nil, PAnsiChar(ExistentFile.FileName));
  597.           rrSkip: begin
  598.                     ReadFileHeaderResult:=RARProcessFile(ArchiveHandle, RAR_SKIP, PAnsiChar(Path), NIL);
  599.                     {$WARN COMBINING_SIGNED_UNSIGNED OFF}
  600.                     fProgressInfo.FileBytesDone:=fProgressInfo.FileBytesDone+hdrData.UnpSize;
  601.                     {$WARN COMBINING_SIGNED_UNSIGNED ON}
  602.                   end;
  603.         end;
  604.  
  605.       end else
  606.         ReadFileHeaderResult:=RARProcessFile(ArchiveHandle, RAR_SKIP, NIL, NIL); //select next file without extracting
  607.  
  608.       if ReadFileHeaderResult<>RAR_SUCCESS then begin
  609.         Result:=False;
  610.         Error(ReadFileHeaderResult,roListFiles);
  611.       end;
  612.  
  613.       if fAbort then
  614.         Result:=False;
  615.     end;
  616.   finally
  617.     CloseArchive;
  618.   end;
  619.   if fAbort then
  620.     Result:=False;
  621. end;
  622.  
  623. function TRAR.Test:boolean;
  624. var
  625.   ReadFileHeaderResult: integer;
  626. begin
  627.   assert(FileExists(fArchiveInformation.FileName));
  628.   fAbort:=False;
  629.   Result:=InitArchive(True);
  630.   if fAbort or (not Result) then exit;
  631.   try
  632.     mySelf:=Self;
  633.     RARSetCallback(Archivehandle,UnRarCallBack,Integer(mySelf));
  634.     if Password<>'' then
  635.       RARSetPassword(ArchiveHandle,PAnsiChar(Password));
  636.     fProgressInfo.TotalSize:=0;
  637.     readFileHeaderResult:=RAR_SUCCESS;
  638.     while (ReadFileHeaderResult=RAR_SUCCESS) and Result do begin
  639.       ReadFileHeaderResult:=RARReadHeaderEx(ArchiveHandle,@hdrData);
  640.       //ReadFileHeaderResult:=RARReadHeader(ArchiveHandle,@hdrData);
  641.  
  642.       if ReadFileHeaderResult=ERAR_END_ARCHIVE then
  643.         break;
  644.  
  645.       if ReadFileHeaderResult<>RAR_SUCCESS then begin
  646.         Result:=False;
  647.         Error(ReadFileHeaderResult,roListFiles);
  648.       end;
  649.  
  650.       fProgressInfo.FileBytesDone:=0;
  651.       fProgressinfo.FileBytesTotal:=hdrData.UnpSize;
  652.       fProgressInfo.FileName:=hdrData.FileNameW;
  653.  
  654.       ReadFileHeaderResult:=RARProcessFile(ArchiveHandle,RAR_TEST,NIL,NIL);
  655.  
  656.       if ReadFileHeaderResult<>RAR_SUCCESS then begin
  657.         Result:=False;
  658.         Error(ReadFileHeaderResult,roListFiles);
  659.       end;
  660.  
  661.       if fAbort then
  662.         Result:=False;
  663.     end;
  664.   finally
  665.     CloseArchive;
  666.   end;
  667. end;
  668.  
  669. procedure TRAR.LoadDLL;
  670. begin
  671.   RARDLLInstance:=LoadLibraryA(PAnsiChar(fDLLName));
  672.   if RARDLLInstance<>0 then begin
  673.     DllLoaded:=True;
  674.     @RAROpenArchive:=GetProcAddress(RARDLLInstance,'RAROpenArchive');
  675.     @RAROpenArchiveEx:=GetProcAddress(RARDLLInstance,'RAROpenArchiveEx');
  676.     @RARCloseArchive:=GetProcAddress(RARDLLInstance,'RARCloseArchive');
  677.     @RARReadHeader:=GetProcAddress(RARDLLInstance,'RARReadHeader');
  678.     @RARReadHeaderEx:=GetProcAddress(RARDLLInstance,'RARReadHeaderEx');
  679.     @RARProcessFile:=GetProcAddress(RARDLLInstance,'RARProcessFile');
  680.     @RARSetCallback:=GetProcAddress(RARDLLInstance,'RARSetCallback');
  681.     @RARSetChangeVolProc:=GetProcAddress(RARDLLInstance,'RARSetChangeVolProc');
  682.     @RARSetProcessDataProc:=GetProcAddress(RARDLLInstance,'RARSetProcessDataProc');
  683.     @RARSetPassword:=GetProcAddress(RARDLLInstance,'RARSetPassword');
  684.     @RARGetDllVersion:=GetProcAddress(RARDLLInstance,'RARGetDllVersion');
  685.     if (@RAROpenArchive=nil) or (@RAROpenArchiveEx=nil) or (@RARCloseArchive=nil)
  686.     or (@RARReadHeader=nil) or (@RARReadHeaderEx=nil) or (@RARProcessFile=nil)
  687.     or (@RARSetCallback=nil) or (@RARSetChangeVolProc=nil) or (@RARSetProcessDataProc=nil)
  688.     or (@RARSetPassword=nil) or (@RARGetDllVersion=nil) then begin
  689.       RARDLLInstance:=0;
  690.       UnloadDLL;
  691.     end;
  692.     if RARGetDllVersion<MIN_RAR_VERSION then
  693.       MessageBox(0,'please download the newest "unrar.dll" file. See www.rarlabs.com','error',0);
  694.   end;
  695. end;
  696.  
  697. procedure TRAR.UnloadDLL;
  698. begin
  699.   if DllLoaded then begin
  700.     FreeLibrary(RARDLLInstance);
  701.     RARDLLInstance:=0;
  702.   end;
  703. end;
  704.  
  705. function TRAR.isDLLLoaded:boolean;
  706. begin
  707.   Result:=RARDLLInstance<>0;
  708. end;
  709.  
  710. function TRAR.GetDllVersion:integer;
  711. begin
  712.   if not isDLLLoaded then
  713.     LoadDLL;
  714.   if not isDLLLoaded then begin
  715.     Error(ERAR_DLL_LOAD_ERROR,roInitArchive);
  716.     Result:=0;
  717.     Exit;
  718.   end;
  719.   Result:=RARGetDllVersion;
  720. end;
  721.  
  722. procedure TRAR.Abort;
  723. begin
  724.   fAbort:=True;
  725. end;
  726.  
  727. procedure TRAR.Error(ErrorCode:integer;Operation:TRAROperation);
  728. begin
  729.   if (ErrorCode=ERAR_DLL_LOAD_ERROR) or
  730.      //(ErrorCode=ERAR_END_ARCHIVE) or
  731.      (ErrorCode=ERAR_NO_MEMORY) or
  732.      (ErrorCode=ERAR_BAD_DATA) or
  733.      (ErrorCode=ERAR_UNKNOWN_FORMAT) or
  734.      (ErrorCode=ERAR_EOPEN) or
  735.      (ErrorCode=ERAR_ECREATE) or
  736.      (ErrorCode=ERAR_ECLOSE) or
  737.      (ErrorCode=ERAR_EREAD) or
  738.      (ErrorCode=ERAR_EWRITE) or
  739.      (ErrorCode=ERAR_SMALL_BUF) or
  740.      (ErrorCode=ERAR_UNKNOWN) then
  741.     fAbort:=True;
  742.  
  743.   if assigned(fOnError) then
  744.     fOnError(Self,ErrorCode,Operation);
  745. end;
  746.  
  747. function TRAR.getVersion:String;
  748. begin
  749.   result:=fVersion;
  750. end;
  751.  
  752. end.
  753.