mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
1178 lines
34 KiB
ObjectPascal
1178 lines
34 KiB
ObjectPascal
{
|
|
Double commander
|
|
-------------------------------------------------------------------------
|
|
Archive File support - class for manage WCX plugins (Version 2.10)
|
|
|
|
Copyright (C) 2006-2008 Koblov Alexander (Alexx2000@mail.ru)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
}
|
|
|
|
unit uWCXmodule;
|
|
|
|
interface
|
|
uses
|
|
uWCXprototypes, uWCXhead, uFileList, uTypes, dynlibs, Classes, uVFSModule,
|
|
uVFSTypes, uVFSUtil, fFileOpDlg, Dialogs, DialogAPI, uClassesEx;
|
|
|
|
{$H+}
|
|
const
|
|
OP_EXTRACT = 0;
|
|
OP_PACK = 1;
|
|
|
|
Type
|
|
TWCXModule = class;
|
|
|
|
PHeaderData = ^THeaderData;
|
|
|
|
{ Packing/Unpacking thread }
|
|
|
|
TWCXCopyThread = class(TThread)
|
|
protected
|
|
procedure Execute; override;
|
|
public
|
|
Operation : Integer;
|
|
WCXModule : TWCXModule;
|
|
end;
|
|
|
|
|
|
{ TWCXModule }
|
|
|
|
TWCXModule = class (TVFSModule)
|
|
private
|
|
FArcFileList : TList;
|
|
FFileList : TFileList;
|
|
FFileMask : String;
|
|
FFlags : Integer;
|
|
FDstPath,
|
|
fFolder : String;
|
|
FFilesSize: Int64;
|
|
FPercent : Double;
|
|
CT : TWCXCopyThread; // Packing/Unpacking thread
|
|
FFileOpDlg: TfrmFileOp; // progress window
|
|
procedure ShowErrorMessage;
|
|
function WCXCopyOut : Boolean; {Extract files from archive}
|
|
function WCXCopyIn : Boolean; {Pack files in archive}
|
|
|
|
procedure CopySelectedWithSubFolders(var flist:TFileList);
|
|
protected
|
|
// module's functions
|
|
//**mandatory:
|
|
OpenArchive : TOpenArchive;
|
|
ReadHeader : TReadHeader;
|
|
ProcessFile : TProcessFile;
|
|
CloseArchive : TCloseArchive;
|
|
//**optional:
|
|
PackFiles : TPackFiles;
|
|
DeleteFiles : TDeleteFiles;
|
|
GetPackerCaps : TGetPackerCaps;
|
|
ConfigurePacker : TConfigurePacker;
|
|
SetChangeVolProc : TSetChangeVolProc;
|
|
SetProcessDataProc : TSetProcessDataProc;
|
|
StartMemPack : TStartMemPack;
|
|
PackToMem : TPackToMem;
|
|
DoneMemPack : TDoneMemPack;
|
|
CanYouHandleThisFile : TCanYouHandleThisFile;
|
|
PackSetDefaultParams : TPackSetDefaultParams;
|
|
// Dialog API
|
|
SetDlgProc: TSetDlgProc;
|
|
FModuleHandle:TLibHandle; // Handle to .DLL or .so
|
|
FArchiveName : String;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
function LoadModule(const sName:String):Boolean;override; {Load WCX plugin}
|
|
procedure UnloadModule;override; {UnLoad WCX plugin}
|
|
|
|
function VFSInit:Boolean;override;
|
|
procedure VFSDestroy;override;
|
|
function VFSCaps : TVFSCaps;override;
|
|
|
|
function VFSConfigure(Parent: THandle):Boolean;override;
|
|
function VFSOpen(const sName:String; bCanYouHandleThisFile : Boolean = False):Boolean;override;
|
|
function VFSClose:Boolean;override;
|
|
function VFSRefresh : Boolean;override;
|
|
|
|
function VFSMkDir(const sDirName:String ):Boolean;override;{Create a directory}
|
|
function VFSRmDir(const sDirName:String):Boolean;override; {Remove a directory}
|
|
|
|
function VFSCopyOut(var flSrcList : TFileList; sDstPath:String; Flags: Integer):Boolean;override;{Extract files from archive}
|
|
function VFSCopyIn(var flSrcList : TFileList; sDstName:String; Flags : Integer):Boolean;override;{Pack files in archive}
|
|
function VFSCopyOutEx(var flSrcList : TFileList; sDstPath:String; Flags: Integer):Boolean;override;{Extract files from archive in thread}
|
|
function VFSCopyInEx(var flSrcList : TFileList; sDstName:String; Flags : Integer):Boolean;override;{Pack files in archive in thread}
|
|
|
|
function VFSRename(const sSrcName, sDstName:String):Boolean;override;{Rename or move file}
|
|
function VFSRun(const sName:String):Boolean;override;
|
|
function VFSDelete(var flNameList:TFileList):Boolean;override;{Delete files from archive}
|
|
|
|
function VFSList(const sDir:String; var fl:TFileList ):Boolean;override;{Return the filelist of archive}
|
|
function VFSMisc : PtrUInt;override;
|
|
end;
|
|
|
|
{ TWCXModuleList }
|
|
|
|
TWCXModuleList = class(TStringList)
|
|
private
|
|
function GetAEnabled(Index: Integer): Boolean;
|
|
function GetAExt(Index: Integer): String;
|
|
function GetAFileName(Index: Integer): String;
|
|
function GetAFlags(Index: Integer): PtrInt;
|
|
procedure SetAEnabled(Index: Integer; const AValue: Boolean);
|
|
procedure SetAFileName(Index: Integer; const AValue: String);
|
|
procedure SetAFlags(Index: Integer; const AValue: PtrInt);
|
|
procedure SetExt(Index: Integer; const AValue: String);
|
|
public
|
|
procedure Load(Ini: TIniFileEx); overload;
|
|
procedure Save(Ini: TIniFileEx); overload;
|
|
function Add(Ext: String; Flags: PtrInt; FileName: String): Integer;
|
|
property FileName[Index: Integer]: String read GetAFileName write SetAFileName;
|
|
property Flags[Index: Integer]: PtrInt read GetAFlags write SetAFlags;
|
|
property Ext[Index: Integer]: String read GetAExt write SetExt;
|
|
property Enabled[Index: Integer]: Boolean read GetAEnabled write SetAEnabled;
|
|
end;
|
|
|
|
function IsBlocked : Boolean;
|
|
|
|
implementation
|
|
uses Forms, SysUtils, Masks, uFileOp, uGlobs, uLog, uOSUtils, LCLProc, uFileProcs,
|
|
uDCUtils, uLng, Controls, fPackInfoDlg, fDialogBox, uGlobsPaths, FileUtil;
|
|
|
|
var
|
|
WCXModule : TWCXModule; // used in ProcessDataProc
|
|
iResult : Integer;
|
|
|
|
constructor TWCXModule.Create;
|
|
begin
|
|
FFilesSize:= 0;
|
|
FPercent := 0;
|
|
end;
|
|
|
|
destructor TWCXModule.Destroy;
|
|
begin
|
|
UnloadModule;
|
|
end;
|
|
|
|
function TWCXModule.LoadModule(const sName:String):Boolean;
|
|
var
|
|
PackDefaultParamStruct : pPackDefaultParamStruct;
|
|
SetDlgProcInfo: TSetDlgProcInfo;
|
|
begin
|
|
FModuleHandle := LoadLibrary(sName);
|
|
Result := (FModuleHandle <> 0);
|
|
if FModuleHandle = 0 then exit;
|
|
//DebugLN('FModuleHandle =', FModuleHandle);
|
|
// mandatory functions
|
|
OpenArchive:= TOpenArchive(GetProcAddress(FModuleHandle,'OpenArchive'));
|
|
@ReadHeader:= GetProcAddress(FModuleHandle,'ReadHeader');
|
|
@ProcessFile:= GetProcAddress(FModuleHandle,'ProcessFile');
|
|
@CloseArchive:= GetProcAddress(FModuleHandle,'CloseArchive');
|
|
if ((@OpenArchive = nil)or(@ReadHeader = nil)or
|
|
(@ProcessFile = nil)or(@CloseArchive = nil)) then
|
|
begin
|
|
OpenArchive := nil;
|
|
ReadHeader:= nil;
|
|
ProcessFile := nil;
|
|
CloseArchive := nil;
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
// optional functions
|
|
@PackFiles:= GetProcAddress(FModuleHandle,'PackFiles');
|
|
@DeleteFiles:= GetProcAddress(FModuleHandle,'DeleteFiles');
|
|
@GetPackerCaps:= GetProcAddress(FModuleHandle,'GetPackerCaps');
|
|
@ConfigurePacker:= GetProcAddress(FModuleHandle,'ConfigurePacker');
|
|
@SetChangeVolProc:= GetProcAddress(FModuleHandle,'SetChangeVolProc');
|
|
@SetProcessDataProc:= GetProcAddress(FModuleHandle,'SetProcessDataProc');
|
|
@StartMemPack:= GetProcAddress(FModuleHandle,'StartMemPack');
|
|
@PackToMem:= GetProcAddress(FModuleHandle,'PackToMem');
|
|
@DoneMemPack:= GetProcAddress(FModuleHandle,'DoneMemPack');
|
|
@CanYouHandleThisFile:= GetProcAddress(FModuleHandle,'CanYouHandleThisFile');
|
|
@PackSetDefaultParams:= GetProcAddress(FModuleHandle,'PackSetDefaultParams');
|
|
// Dialog API function
|
|
@SetDlgProc:= GetProcAddress(FModuleHandle,'SetDlgProc');
|
|
|
|
if Assigned(PackSetDefaultParams) then
|
|
begin
|
|
with PackDefaultParamStruct^ do
|
|
begin
|
|
Size := SizeOf(PackDefaultParamStruct^);
|
|
PluginInterfaceVersionLow := 10;
|
|
PluginInterfaceVersionHi := 2;
|
|
DefaultIniName := '';
|
|
end;
|
|
PackSetDefaultParams(PackDefaultParamStruct);
|
|
end;
|
|
|
|
// Dialog API
|
|
if Assigned(SetDlgProc) then
|
|
begin
|
|
with SetDlgProcInfo do
|
|
begin
|
|
PluginDir:= PWideChar(WideString(ExtractFilePath(sName)));
|
|
PluginConfDir:= PWideChar(UTF8Decode(gpIniDir));
|
|
InputBox:= @fDialogBox.InputBox;
|
|
MessageBox:= @fDialogBox.MessageBox;
|
|
DialogBox:= @fDialogBox.DialogBox;
|
|
DialogBoxEx:= @fDialogBox.DialogBoxEx;
|
|
SendDlgMsg:= @fDialogBox.SendDlgMsg;
|
|
end;
|
|
SetDlgProc(SetDlgProcInfo);
|
|
end;
|
|
end;
|
|
|
|
procedure TWCXModule.UnloadModule;
|
|
begin
|
|
if FModuleHandle <> 0 then
|
|
FreeLibrary(FModuleHandle);
|
|
FModuleHandle := 0;
|
|
@OpenArchive:= nil;
|
|
@ReadHeader:= nil;
|
|
@ProcessFile:= nil;
|
|
@CloseArchive:= nil;
|
|
@PackFiles:= nil;
|
|
@DeleteFiles:= nil;
|
|
@GetPackerCaps:= nil;
|
|
@ConfigurePacker:= nil;
|
|
@SetChangeVolProc:= nil;
|
|
@SetProcessDataProc:= nil;
|
|
@StartMemPack:= nil;
|
|
@PackToMem:= nil;
|
|
@DoneMemPack:= nil;
|
|
@CanYouHandleThisFile:= nil;
|
|
@PackSetDefaultParams:= nil;
|
|
end;
|
|
|
|
procedure ShowErrorMsg(iErrorMsg : Integer);
|
|
var
|
|
sErrorMsg : String;
|
|
begin
|
|
case iErrorMsg of
|
|
E_END_ARCHIVE : sErrorMsg := rsMsgErrEndArchive;
|
|
E_NO_MEMORY : sErrorMsg := rsMsgErrNoMemory;
|
|
E_BAD_DATA : sErrorMsg := rsMsgErrBadData;
|
|
E_BAD_ARCHIVE : sErrorMsg := rsMsgErrBadArchive;
|
|
E_UNKNOWN_FORMAT : sErrorMsg := rsMsgErrUnknownFormat;
|
|
E_EOPEN : sErrorMsg := rsMsgErrEOpen;
|
|
E_ECREATE : sErrorMsg := rsMsgErrECreate;
|
|
E_ECLOSE : sErrorMsg := rsMsgErrEClose;
|
|
E_EREAD : sErrorMsg := rsMsgErrERead;
|
|
E_EWRITE : sErrorMsg := rsMsgErrEWrite;
|
|
E_SMALL_BUF : sErrorMsg := rsMsgErrSmallBuf;
|
|
E_EABORTED : sErrorMsg := rsMsgErrEAborted;
|
|
E_NO_FILES : sErrorMsg := rsMsgErrNoFiles;
|
|
E_TOO_MANY_FILES : sErrorMsg := rsMsgErrTooManyFiles;
|
|
E_NOT_SUPPORTED : sErrorMsg := rsMsgErrNotSupported;
|
|
end;
|
|
|
|
// write log error
|
|
if (log_arc_op in gLogOptions) and (log_errors in gLogOptions) then
|
|
logWrite(rsMsgLogError + sErrorMsg, lmtError);
|
|
|
|
// Standart error modal dialog
|
|
ShowMessage(sErrorMsg);
|
|
end;
|
|
|
|
function ChangeVolProc(ArcName : Pchar; Mode:Longint):Longint; stdcall;
|
|
begin
|
|
case Mode of
|
|
PK_VOL_ASK:
|
|
ArcName := PChar(UTF8ToSys(Dialogs.InputBox ('Double Commander', rsMsgSelLocNextVol, SysToUTF8(ArcName))));
|
|
PK_VOL_NOTIFY:
|
|
ShowMessage(rsMsgNextVolUnpack);
|
|
end;
|
|
end;
|
|
|
|
function ProcessDataProc(FileName: PChar; Size: Integer): Integer; stdcall;
|
|
begin
|
|
//DebugLn('Working ' + FileName + ' Size = ' + IntToStr(Size));
|
|
|
|
Result := 1;
|
|
with WCXModule do
|
|
begin
|
|
if FFileOpDlg.ModalResult = mrCancel then // Cancel operation
|
|
Result := 0;
|
|
|
|
FFileOpDlg.sFileName := SysToUTF8(FileName);
|
|
|
|
if not (Size < 0) then
|
|
begin
|
|
FPercent := FPercent + ((Size * 100) / FFilesSize);
|
|
//DebugLn('Percent = ' + IntToStr(Round(FPercent)));
|
|
|
|
FFileOpDlg.iProgress1Pos := 100;
|
|
FFileOpDlg.iProgress2Pos := Round(FPercent);
|
|
end
|
|
else // For plugins which unpack in CloseArchive
|
|
if (Size >= -100) and (Size <= -1) then // first percent bar
|
|
begin
|
|
FFileOpDlg.iProgress1Pos := (Size * -1);
|
|
//DebugLn('Working ' + FileName + ' Percent1 = ' + IntToStr(FFileOpDlg.iProgress1Pos));
|
|
end
|
|
else if (Size >= -1100) and (Size <= -1000) then // second percent bar
|
|
begin
|
|
FFileOpDlg.iProgress2Pos := (Size * -1) - 1000;
|
|
//DebugLn('Working ' + FileName + ' Percent2 = ' + IntToStr(FFileOpDlg.iProgress2Pos));
|
|
end;
|
|
|
|
|
|
if Assigned(CT) then
|
|
CT.Synchronize(FFileOpDlg.UpdateDlg)
|
|
else
|
|
begin
|
|
FFileOpDlg.UpdateDlg;
|
|
Application.ProcessMessages;
|
|
end;
|
|
end; //with
|
|
end;
|
|
|
|
procedure TWCXModule.ShowErrorMessage;
|
|
begin
|
|
ShowErrorMsg(iResult);
|
|
end;
|
|
|
|
function TWCXModule.VFSInit: Boolean;
|
|
begin
|
|
|
|
end;
|
|
|
|
procedure TWCXModule.VFSDestroy;
|
|
begin
|
|
|
|
end;
|
|
|
|
function TWCXModule.VFSCaps: TVFSCaps;
|
|
begin
|
|
Result := [];
|
|
Include(Result, VFS_CAPS_COPYOUT);
|
|
if Assigned(PackFiles) then
|
|
Include(Result, VFS_CAPS_COPYIN);
|
|
if Assigned(DeleteFiles) then
|
|
Include(Result, VFS_CAPS_DELETE);
|
|
end;
|
|
|
|
function TWCXModule.VFSConfigure(Parent: THandle): Boolean;
|
|
begin
|
|
if @ConfigurePacker <> nil then
|
|
ConfigurePacker(Parent, FModuleHandle);
|
|
end;
|
|
|
|
|
|
function TWCXModule.VFSOpen(const sName: String; bCanYouHandleThisFile : Boolean = False): Boolean;
|
|
var
|
|
ArcHandle : THandle;
|
|
ArcFile : tOpenArchiveData;
|
|
ArcHeader : THeaderData;
|
|
HeaderData : PHeaderData;
|
|
bHasDir : Boolean;
|
|
sDirs : TStringList;
|
|
I : Integer;
|
|
begin
|
|
bHasDir := False;
|
|
sDirs := TStringList.Create;
|
|
|
|
FArchiveName := sName;
|
|
DebugLN('FArchiveName = ' + FArchiveName);
|
|
|
|
if not mbFileAccess(FArchiveName, fmOpenRead) then
|
|
begin
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
|
|
if bCanYouHandleThisFile and Assigned(CanYouHandleThisFile) then
|
|
begin
|
|
Result := CanYouHandleThisFile(PChar(UTF8ToSys(sName)));
|
|
if not Result then Exit;
|
|
end;
|
|
|
|
DebugLN('Open Archive');
|
|
|
|
(*Open Archive*)
|
|
FillChar(ArcFile, SizeOf(ArcFile), #0);
|
|
ArcFile.ArcName := PChar(UTF8ToSys(sName));
|
|
ArcFile.OpenMode := PK_OM_LIST;
|
|
|
|
try
|
|
ArcHandle := OpenArchive(ArcFile);
|
|
except
|
|
ArcHandle := 0;
|
|
end;
|
|
|
|
if ArcHandle = 0 then
|
|
begin
|
|
if not bCanYouHandleThisFile then
|
|
ShowErrorMsg(ArcFile.OpenResult);
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
{
|
|
WCXModule := Self; // set WCXModule variable to current module
|
|
SetChangeVolProc(ArcHandle, ChangeVolProc);
|
|
SetProcessDataProc(ArcHandle, ProcessDataProc);
|
|
}
|
|
|
|
DebugLN('Get File List');
|
|
(*Get File List*)
|
|
FillChar(ArcHeader, SizeOf(ArcHeader), #0);
|
|
FArcFileList := TList.Create;
|
|
|
|
try
|
|
while (ReadHeader(ArcHandle, ArcHeader) = 0) do
|
|
begin
|
|
New(HeaderData);
|
|
HeaderData^ := ArcHeader;
|
|
//****************************
|
|
(* if plugin is not give a list of folders *)
|
|
if (sDirs.Count > 0) or not bHasDir then
|
|
begin
|
|
bHasDir := FPS_ISDIR(HeaderData^.FileAttr);
|
|
GetDirs(String(HeaderData^.FileName), sDirs);
|
|
end;
|
|
//****************************
|
|
FillChar(ArcHeader, SizeOf(ArcHeader), #0);
|
|
// get next file
|
|
iResult := ProcessFile(ArcHandle, PK_SKIP, nil, nil);
|
|
|
|
//Check for errors
|
|
if iResult <> 0 then
|
|
ShowErrorMessage;
|
|
|
|
(* if archive keeps some folders, but some do not keep *)
|
|
if (sDirs.Count > 0) and (bHasDir) then
|
|
Continue;
|
|
FArcFileList.Add(HeaderData);
|
|
end; // while
|
|
|
|
(* if plugin is not give a list of folders *)
|
|
if not bHasDir then
|
|
begin
|
|
for I := 0 to sDirs.Count - 1 do
|
|
begin
|
|
FillChar(ArcHeader, SizeOf(ArcHeader), #0);
|
|
ArcHeader.FileName := sDirs.Strings[I];
|
|
ArcHeader.FileAttr := faFolder;
|
|
ArcHeader.FileTime := mbFileAge(FArchiveName);
|
|
New(HeaderData);
|
|
HeaderData^ := ArcHeader;
|
|
FArcFileList.Add(HeaderData);
|
|
end;
|
|
end;
|
|
finally
|
|
sDirs.Free;
|
|
CloseArchive(ArcHandle);
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TWCXModule.VFSClose: Boolean;
|
|
begin
|
|
|
|
end;
|
|
|
|
function TWCXModule.VFSRefresh: Boolean;
|
|
begin
|
|
Result := VFSOpen(FArchiveName)
|
|
end;
|
|
|
|
function TWCXModule.VFSMkDir(const sDirName: String): Boolean;
|
|
begin
|
|
|
|
end;
|
|
|
|
function TWCXModule.VFSRmDir(const sDirName: String): Boolean;
|
|
begin
|
|
|
|
end;
|
|
|
|
function GetFileList(var fl:TFileList) : String;
|
|
var
|
|
I, Count : Integer;
|
|
FileList : String;
|
|
begin
|
|
I := 1;
|
|
Count := fl.Count - 1;
|
|
FileList := fl.GetItem(0)^.sName;
|
|
while I <= Count do
|
|
begin
|
|
FileList := FileList + #0 + fl.GetItem(I)^.sName;
|
|
I := I + 1;
|
|
end;
|
|
FileList := FileList + #0#0;
|
|
//DebugLn('FileList := ' + FileList);
|
|
Result := FileList;
|
|
end;
|
|
|
|
function TWCXModule.WCXCopyOut : Boolean;
|
|
var
|
|
ArcHandle : THandle;
|
|
ArcFile : tOpenArchiveData;
|
|
ArcHeader : THeaderData;
|
|
Extract : Boolean;
|
|
Count, I : Integer;
|
|
Folder : String;
|
|
begin
|
|
FPercent := 0;
|
|
|
|
FFileMask := ExtractFileName(FDstPath);
|
|
if FFileMask = '' then FFileMask := '*'; // extract all selected files/folders
|
|
FDstPath := ExtractFilePath(FDstPath);
|
|
|
|
(* Get current folder in archive *)
|
|
Folder := FFileList.CurrentDirectory; //LowDirLevel(FFileList.GetItem(0)^.sName);
|
|
|
|
(* Get relative path *)
|
|
IncludeFileInList(FArchiveName, Folder);
|
|
|
|
FFolder := Folder;
|
|
|
|
DebugLN('Folder = ' + Folder);
|
|
|
|
//sDstPath := ExcludeTrailingPathDelimiter(sDstPath);
|
|
|
|
CopySelectedWithSubFolders(FFileList);
|
|
DebugLN('Extract file = ' + FArchiveName + DirectorySeparator + ArcHeader.FileName);
|
|
|
|
|
|
Count := FFileList.Count;
|
|
FillChar(ArcFile, SizeOf(ArcFile), #0);
|
|
ArcFile.ArcName := PChar(UTF8ToSys(FArchiveName));
|
|
ArcFile.OpenMode := PK_OM_EXTRACT;
|
|
ArcHandle := OpenArchive(ArcFile);
|
|
|
|
if ArcHandle = 0 then
|
|
begin
|
|
if Assigned(CT) then
|
|
begin
|
|
iResult := ArcFile.OpenResult;
|
|
CT.Synchronize(ShowErrorMessage);
|
|
end
|
|
else
|
|
ShowErrorMsg(ArcFile.OpenResult);
|
|
Result := False;
|
|
Exit;
|
|
end;
|
|
|
|
WCXModule := Self; // set WCXModule variable to current module
|
|
SetChangeVolProc(ArcHandle, ChangeVolProc);
|
|
SetProcessDataProc(ArcHandle, ProcessDataProc);
|
|
|
|
|
|
FillChar(ArcHeader, SizeOf(ArcHeader), #0);
|
|
while (ReadHeader(ArcHandle, ArcHeader) = 0) do
|
|
begin
|
|
|
|
if FFileList.CheckFileName(SysToUTF8(ArcHeader.FileName)) >= 0 then // Want To Extract This File
|
|
begin
|
|
//DebugLn(FDstPath + ExtractDirLevel(Folder, PathDelim + ArcHeader.FileName));
|
|
|
|
if (FFileMask <> '*.*') and (FFileMask <> '*') then
|
|
ForceDirectory(ExtractFilePath(FDstPath + ExtractDirLevel(Folder, PathDelim + SysToUTF8(ArcHeader.FileName))));
|
|
|
|
|
|
iResult := ProcessFile(ArcHandle, PK_EXTRACT, nil, PChar(UTF8ToSys(FDstPath) + ExtractDirLevel(UTF8ToSys(Folder), PathDelim + ArcHeader.FileName)));
|
|
|
|
//Check for errors
|
|
if iResult <> 0 then
|
|
begin
|
|
if Assigned(CT) then
|
|
begin
|
|
// write log error
|
|
if (log_arc_op in gLogOptions) and (log_errors in gLogOptions) then
|
|
logWrite(CT, Format(rsMsgLogError+rsMsgLogExtract, [FArchiveName + PathDelim + SysToUTF8(ArcHeader.FileName)+' -> '+FDstPath+ExtractDirLevel(Folder, PathDelim + SysToUTF8(ArcHeader.FileName))]), lmtError);
|
|
// Standart error modal dialog
|
|
CT.Synchronize(ShowErrorMessage)
|
|
end
|
|
else
|
|
begin
|
|
// write log error
|
|
if (log_arc_op in gLogOptions) and (log_errors in gLogOptions) then
|
|
logWrite(Format(rsMsgLogError+rsMsgLogExtract, [FArchiveName + PathDelim + SysToUTF8(ArcHeader.FileName)+' -> '+FDstPath+ExtractDirLevel(Folder, PathDelim + SysToUTF8(ArcHeader.FileName))]), lmtError);
|
|
// Standart error modal dialog
|
|
ShowErrorMessage;
|
|
end;
|
|
// user abort operation
|
|
if iResult = E_EABORTED then Break;
|
|
end // Error
|
|
else
|
|
begin
|
|
if Assigned(CT) then
|
|
begin
|
|
// write log success
|
|
if (log_arc_op in gLogOptions) and (log_success in gLogOptions) then
|
|
logWrite(CT, Format(rsMsgLogSuccess+rsMsgLogExtract, [FArchiveName + PathDelim + SysToUTF8(ArcHeader.FileName)+' -> '+FDstPath+ExtractDirLevel(Folder, PathDelim + SysToUTF8(ArcHeader.FileName))]), lmtSuccess);
|
|
end
|
|
else
|
|
begin
|
|
// write log success
|
|
if (log_arc_op in gLogOptions) and (log_success in gLogOptions) then
|
|
logWrite(Format(rsMsgLogSuccess+rsMsgLogExtract, [FArchiveName + PathDelim + SysToUTF8(ArcHeader.FileName)+' -> '+FDstPath+ExtractDirLevel(Folder, PathDelim + SysToUTF8(ArcHeader.FileName))]), lmtSuccess);
|
|
end;
|
|
end; // Success
|
|
|
|
end // CheckFileName
|
|
else // Skip
|
|
begin
|
|
iResult := ProcessFile(ArcHandle, PK_SKIP, nil, nil);
|
|
|
|
//Check for errors
|
|
if iResult <> 0 then
|
|
if Assigned(CT) then
|
|
CT.Synchronize(ShowErrorMessage)
|
|
else
|
|
ShowErrorMessage;
|
|
end; // Skip
|
|
FillChar(ArcHeader, SizeOf(ArcHeader), #0);
|
|
end;
|
|
CloseArchive(ArcHandle);
|
|
Result := True;
|
|
end;
|
|
|
|
function TWCXModule.WCXCopyIn : Boolean;
|
|
var
|
|
FileList, Folder, pDstPath : PChar;
|
|
I : Integer;
|
|
begin
|
|
DebugLN('VFSCopyIn =' + FArchiveName);
|
|
FPercent := 0;
|
|
New(FileList);
|
|
New(Folder);
|
|
FDstPath := ExtractDirLevel(FArchiveName + PathDelim, FDstPath);
|
|
FDstPath := ExcludeTrailingPathDelimiter(FDstPath);
|
|
|
|
if FDstPath = '' then
|
|
pDstPath := nil
|
|
else
|
|
pDstPath := PChar(UTF8ToSys(FDstPath));
|
|
|
|
DebugLN('sDstPath == ' + FDstPath);
|
|
|
|
(* Add in file list files from subfolders *)
|
|
FillAndCount(FFileList, FFilesSize);
|
|
|
|
DebugLN('Curr Dir := ' + FFileList.CurrentDirectory);
|
|
Folder := PChar(UTF8ToSys(FFileList.CurrentDirectory));
|
|
|
|
|
|
(* Convert TFileList into PChar *)
|
|
FileList := PChar(UTF8ToSys(GetFileList(FFileList)));
|
|
|
|
WCXModule := Self; // set WCXModule variable to current module
|
|
SetChangeVolProc(0, ChangeVolProc);
|
|
SetProcessDataProc(0, ProcessDataProc);
|
|
|
|
iResult := PackFiles(PChar(UTF8ToSys(FArchiveName)), pDstPath, Folder, FileList, FFlags);
|
|
|
|
//Check for errors
|
|
if iResult <> 0 then
|
|
begin
|
|
if Assigned(CT) then
|
|
begin
|
|
// write log error
|
|
if (log_arc_op in gLogOptions) and (log_errors in gLogOptions) then
|
|
logWrite(CT, Format(rsMsgLogError+rsMsgLogPack, [FArchiveName]), lmtError);
|
|
// Standart error modal dialog
|
|
CT.Synchronize(ShowErrorMessage)
|
|
end
|
|
else
|
|
begin
|
|
// write log error
|
|
if (log_arc_op in gLogOptions) and (log_errors in gLogOptions) then
|
|
logWrite(Format(rsMsgLogError+rsMsgLogPack, [FArchiveName]), lmtError);
|
|
// Standart error modal dialog
|
|
ShowErrorMessage;
|
|
end;
|
|
end // Error
|
|
else
|
|
begin
|
|
if Assigned(CT) then
|
|
begin
|
|
// write log success
|
|
if (log_arc_op in gLogOptions) and (log_success in gLogOptions) then
|
|
logWrite(CT, Format(rsMsgLogSuccess+rsMsgLogPack, [FArchiveName]), lmtSuccess);
|
|
end
|
|
else
|
|
begin
|
|
// write log success
|
|
if (log_arc_op in gLogOptions) and (log_success in gLogOptions) then
|
|
logWrite(Format(rsMsgLogSuccess+rsMsgLogPack, [FArchiveName]), lmtSuccess);
|
|
end;
|
|
end; // Success
|
|
end;
|
|
|
|
procedure TWCXModule.CopySelectedWithSubFolders(var flist:TFileList);
|
|
|
|
procedure SelectFilesInSubfolders(var fl : TFileList; sDir : String);
|
|
var
|
|
fr : PFileRecItem;
|
|
I, Count : Integer;
|
|
CurrFileName : String; // Current file name
|
|
begin
|
|
if (FFileMask = '*.*') or (FFileMask = '*') then
|
|
ForceDirectory(FDstPath + ExtractDirLevel(FFolder, PathDelim + sDir));
|
|
|
|
//DebugLN('ForceDirectory = ' + FDstPath + ExtractDirLevel(FFolder, PathDelim + sDir));
|
|
|
|
Count := FArcFileList.Count - 1;
|
|
for I := 0 to Count do
|
|
begin
|
|
CurrFileName := SysToUTF8(PathDelim + PHeaderData(FArcFileList.Items[I])^.FileName);
|
|
|
|
//DebugLN('sDir = ', sDir);
|
|
//DebugLN('In folder = ' + CurrFileName);
|
|
|
|
if not IncludeFileInList(sDir + PathDelim, CurrFileName) then
|
|
Continue;
|
|
|
|
if (FFileMask <> '*.*') and (FFileMask <> '*') and
|
|
not FPS_ISDIR(PHeaderData(FArcFileList.Items[I])^.FileAttr) and
|
|
not(MatchesMaskList(CurrFileName, FFileMask)) then
|
|
Continue;
|
|
|
|
// DebugLN('In folder = ' + CurrFileName);
|
|
|
|
New(fr);
|
|
with fr^, PHeaderData(FArcFileList.Items[I])^ do
|
|
begin
|
|
sName := {FArchiveName + PathDelim +} SysToUTF8(FileName);
|
|
iMode := FileAttr;
|
|
if FPS_ISDIR(iMode) then
|
|
begin
|
|
sExt:='';
|
|
//DebugLN('SelectFilesInSubfolders = ' + FileName);
|
|
if (FFileMask = '*.*') or (FFileMask = '*') then
|
|
fl.AddItem(fr);
|
|
SelectFilesInSubfolders(fl, SysToUTF8(FileName));
|
|
end
|
|
else
|
|
begin
|
|
fl.AddItem(fr);
|
|
inc(FFilesSize, UnpSize);
|
|
end;
|
|
end; //with
|
|
end;
|
|
end;
|
|
|
|
|
|
var
|
|
xIndex:Integer;
|
|
fri:TFileRecItem;
|
|
Newfl : TFileList;
|
|
Count : Integer;
|
|
begin
|
|
Newfl := TFileList.Create;
|
|
Count := flist.Count-1;
|
|
for xIndex:=0 to Count do
|
|
begin
|
|
fri:=flist.GetItem(xIndex)^;
|
|
|
|
|
|
fri.sName := ExtractDirLevel(FArchiveName, fri.sName);
|
|
|
|
if fri.sName[1] = PathDelim then
|
|
Delete(fri.sName, 1, 1);
|
|
|
|
if (FFileMask <> '*.*') and (FFileMask <> '*') and not(MatchesMaskList(fri.sName, FFileMask) or FPS_ISDIR(fri.iMode)) then
|
|
Continue;
|
|
|
|
|
|
//DebugLn('Curr File = ' + fri.sName);
|
|
|
|
if FPS_ISDIR(fri.iMode) then
|
|
begin
|
|
if (FFileMask = '*.*') or (FFileMask = '*') then
|
|
Newfl.AddItem(@fri);
|
|
SelectFilesInSubfolders(Newfl, fri.sName);
|
|
end
|
|
else
|
|
begin
|
|
Newfl.AddItem(@fri);
|
|
inc(FFilesSize, fri.iSize);
|
|
end;
|
|
|
|
end; //for
|
|
FreeAndNil(flist);
|
|
flist := Newfl;
|
|
end;
|
|
|
|
{Extract files from archive}
|
|
|
|
function TWCXModule.VFSCopyOut(var flSrcList: TFileList; sDstPath: String;
|
|
Flags: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
try
|
|
FFileOpDlg:= TfrmFileOp.Create(nil);
|
|
FFileOpDlg.Show;
|
|
FFileOpDlg.iProgress1Max:=100;
|
|
FFileOpDlg.iProgress2Max:=100;
|
|
FFileOpDlg.Caption := rsDlgExtract;
|
|
|
|
FFileList := flSrcList;
|
|
FDstPath := sDstPath;
|
|
FFlags := Flags;
|
|
|
|
CT := nil;
|
|
WCXCopyOut;
|
|
FFileOpDlg.Close;
|
|
FFileOpDlg.Free;
|
|
FFileOpDlg := nil;
|
|
except
|
|
FFileOpDlg := nil;
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
{Pack files}
|
|
|
|
function TWCXModule.VFSCopyIn(var flSrcList: TFileList; sDstName: String; Flags : Integer
|
|
): Boolean;
|
|
begin
|
|
Result := True;
|
|
try
|
|
FFileOpDlg:= TfrmFileOp.Create(nil);
|
|
FFileOpDlg.Show;
|
|
FFileOpDlg.iProgress1Max:=100;
|
|
FFileOpDlg.iProgress2Max:=100;
|
|
FFileOpDlg.Caption := rsDlgPack;
|
|
|
|
FFileList := flSrcList;
|
|
FDstPath := sDstName;
|
|
FFlags := Flags;
|
|
|
|
CT := nil;
|
|
WCXCopyIn;
|
|
FFileOpDlg.Close;
|
|
FFileOpDlg.Free;
|
|
FFileOpDlg := nil;
|
|
except
|
|
FFileOpDlg := nil;
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
{Extract files from archive in thread}
|
|
|
|
function TWCXModule.VFSCopyOutEx(var flSrcList: TFileList; sDstPath: String;
|
|
Flags: Integer): Boolean;
|
|
begin
|
|
Result := True;
|
|
try
|
|
FFileOpDlg:= TfrmFileOp.Create(nil);
|
|
FFileOpDlg.Show;
|
|
FFileOpDlg.iProgress1Max:=100;
|
|
FFileOpDlg.iProgress2Max:=100;
|
|
FFileOpDlg.Caption := rsDlgExtract;
|
|
|
|
FFileList := flSrcList;
|
|
FDstPath := sDstPath;
|
|
|
|
CT := TWCXCopyThread.Create(True);
|
|
CT.FreeOnTerminate := True;
|
|
CT.Operation := OP_EXTRACT;
|
|
CT.WCXModule := Self;
|
|
FFileOpDlg.Thread := TThread(CT);
|
|
CT.Resume;
|
|
except
|
|
FFileOpDlg := nil;
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
{Pack files in thread}
|
|
|
|
function TWCXModule.VFSCopyInEx(var flSrcList: TFileList; sDstName: String; Flags : Integer
|
|
): Boolean;
|
|
begin
|
|
Result := True;
|
|
try
|
|
FFileOpDlg:= TfrmFileOp.Create(nil);
|
|
FFileOpDlg.Show;
|
|
FFileOpDlg.iProgress1Max:=100;
|
|
FFileOpDlg.iProgress2Max:=100;
|
|
FFileOpDlg.Caption := rsDlgPack;
|
|
|
|
FFileList := flSrcList;
|
|
FDstPath := sDstName;
|
|
FFlags := Flags;
|
|
|
|
CT := TWCXCopyThread.Create(True);
|
|
CT.FreeOnTerminate := True;
|
|
CT.Operation := OP_PACK;
|
|
CT.WCXModule := Self;
|
|
FFileOpDlg.Thread := TThread(CT);
|
|
CT.Resume;
|
|
except
|
|
FFileOpDlg := nil;
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function TWCXModule.VFSRename(const sSrcName, sDstName: String): Boolean;
|
|
begin
|
|
|
|
end;
|
|
|
|
function TWCXModule.VFSRun(const sName: String): Boolean;
|
|
var
|
|
iCount, I: Integer;
|
|
begin
|
|
//DebugLn(fFolder + sName);
|
|
|
|
iCount := FArcFileList.Count - 1;
|
|
for I := 0 to iCount do
|
|
begin
|
|
//DebugLn(PHeaderData(FArcFileList.Items[I])^.FileName);
|
|
if (PathDelim + PHeaderData(FArcFileList.Items[I])^.FileName) = UTF8ToSys(fFolder + sName) then
|
|
Break;
|
|
end;
|
|
Result:= ShowPackInfoDlg(Self, PHeaderData(FArcFileList.Items[I])^);
|
|
end;
|
|
|
|
function TWCXModule.VFSDelete(var flNameList: TFileList): Boolean;
|
|
var
|
|
Folder : String;
|
|
begin
|
|
// DebugLN('Folder = ' + Folder);
|
|
try
|
|
FFileOpDlg:= TfrmFileOp.Create(nil);
|
|
FFileOpDlg.Show;
|
|
FFileOpDlg.iProgress1Max:=100;
|
|
FFileOpDlg.iProgress2Max:=100;
|
|
FFileOpDlg.Caption := rsDlgDel;
|
|
|
|
CT := nil;
|
|
|
|
WCXModule := Self; // set WCXModule variable to current module
|
|
SetChangeVolProc(0, ChangeVolProc);
|
|
SetProcessDataProc(0, ProcessDataProc);
|
|
|
|
CopySelectedWithSubFolders(flNameList);
|
|
|
|
DeleteFiles(PChar(UTF8ToSys(FArchiveName)), PChar(UTF8ToSys(GetFileList(flNameList))));
|
|
|
|
FFileOpDlg.Close;
|
|
FFileOpDlg.Free;
|
|
FFileOpDlg := nil;
|
|
except
|
|
FFileOpDlg := nil;
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function TWCXModule.VFSList(const sDir: String; var fl: TFileList): Boolean;
|
|
var
|
|
fr : PFileRecItem;
|
|
I, Count : Integer;
|
|
CurrFileName : String; // Current file name
|
|
begin
|
|
fl.Clear;
|
|
fFolder:= sDir; // save current folder
|
|
AddUpLevel(LowDirLevel(sDir), fl);
|
|
|
|
DebugLN('LowDirLevel(sDir) = ' + LowDirLevel(sDir));
|
|
|
|
Count := FArcFileList.Count - 1;
|
|
for I := 0 to Count do
|
|
begin
|
|
CurrFileName := SysToUTF8(PathDelim + PHeaderData(FArcFileList.Items[I])^.FileName);
|
|
|
|
//DebugLn(CurrFileName);
|
|
|
|
if not IncludeFileInList(sDir, CurrFileName) then
|
|
Continue;
|
|
|
|
//DebugLN('In folder = ' + CurrFileName);
|
|
|
|
New(fr);
|
|
with fr^, PHeaderData(FArcFileList.Items[I])^ do
|
|
begin
|
|
sName := CurrFileName;
|
|
iMode := FileAttr;
|
|
sModeStr := AttrToStr(iMode);
|
|
bLinkIsDir := False;
|
|
bSelected := False;
|
|
if FPS_ISDIR(iMode) then
|
|
sExt:=''
|
|
else
|
|
sExt:=ExtractFileExt(CurrFileName);
|
|
sNameNoExt:=Copy(CurrFileName,1,length(CurrFileName)-length(sExt));
|
|
sPath := sDir;
|
|
try
|
|
fTimeI := FileDateToDateTime(FileTime);
|
|
except
|
|
fTimeI := 0;
|
|
end;
|
|
sTime := FormatDateTime(gDateTimeFormat, fTimeI);
|
|
iSize := UnpSize;
|
|
end; //with
|
|
fl.AddItem(fr);
|
|
end;
|
|
end;
|
|
|
|
function TWCXModule.VFSMisc: PtrUInt;
|
|
begin
|
|
if Assigned(GetPackerCaps) then
|
|
Result := GetPackerCaps
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
{ TWCXCopyThread }
|
|
|
|
procedure TWCXCopyThread.Execute;
|
|
|
|
begin
|
|
// main archive thread code started here
|
|
try
|
|
with WCXModule do
|
|
begin
|
|
case Operation of
|
|
OP_EXTRACT:
|
|
begin
|
|
WCXCopyOut;
|
|
end;
|
|
OP_PACK:
|
|
begin
|
|
WCXCopyIn;
|
|
end;
|
|
end; //case
|
|
Synchronize(FFileOpDlg.Close);
|
|
Synchronize(FFileOpDlg.Free);
|
|
FFileOpDlg := nil;
|
|
end; //with
|
|
except
|
|
DebugLN('Error in "WCXCopyThread.Execute"');
|
|
end;
|
|
end;
|
|
|
|
function IsBlocked : Boolean;
|
|
begin
|
|
Result := Assigned(WCXModule);
|
|
if Result then
|
|
with WCXModule do
|
|
begin
|
|
Result := Assigned(FFileOpDlg);
|
|
if Result then
|
|
if Assigned(CT) then
|
|
CT.Synchronize(FFileOpDlg.ShowOnTop)
|
|
else
|
|
FFileOpDlg.ShowOnTop;
|
|
end; // with
|
|
end;
|
|
|
|
{ TWCXModuleList }
|
|
|
|
function TWCXModuleList.GetAEnabled(Index: Integer): Boolean;
|
|
begin
|
|
Result:= Boolean(Objects[Index]);
|
|
end;
|
|
|
|
function TWCXModuleList.GetAExt(Index: Integer): String;
|
|
begin
|
|
Result:= Names[Index];
|
|
end;
|
|
|
|
function TWCXModuleList.GetAFileName(Index: Integer): String;
|
|
var
|
|
sCurrPlugin: String;
|
|
iPosComma : Integer;
|
|
begin
|
|
sCurrPlugin:= ValueFromIndex[Index];
|
|
iPosComma:= Pos(',', sCurrPlugin);
|
|
//get file name
|
|
Result:= Copy(sCurrPlugin, iPosComma + 1, Length(sCurrPlugin) - iPosComma);
|
|
end;
|
|
|
|
function TWCXModuleList.GetAFlags(Index: Integer): PtrInt;
|
|
var
|
|
sCurrPlugin: String;
|
|
iPosComma : Integer;
|
|
begin
|
|
sCurrPlugin:= ValueFromIndex[Index];
|
|
iPosComma:= Pos(',', sCurrPlugin);
|
|
// get packer flags
|
|
Result:= StrToInt(Copy(sCurrPlugin, 1, iPosComma-1));
|
|
end;
|
|
|
|
procedure TWCXModuleList.SetAEnabled(Index: Integer; const AValue: Boolean);
|
|
begin
|
|
Objects[Index]:= TObject(AValue);
|
|
end;
|
|
|
|
procedure TWCXModuleList.SetAFileName(Index: Integer; const AValue: String);
|
|
begin
|
|
ValueFromIndex[Index]:= IntToStr(GetAFlags(Index)) + #44 + AValue;
|
|
end;
|
|
|
|
procedure TWCXModuleList.SetAFlags(Index: Integer; const AValue: PtrInt);
|
|
begin
|
|
ValueFromIndex[Index]:= IntToStr(AValue) + #44 + GetAFileName(Index);
|
|
end;
|
|
|
|
procedure TWCXModuleList.SetExt(Index: Integer; const AValue: String);
|
|
var
|
|
sValue : String;
|
|
begin
|
|
sValue:= ValueFromIndex[Index];
|
|
Self[Index]:= AValue + '=' + sValue;
|
|
end;
|
|
|
|
procedure TWCXModuleList.Load(Ini: TIniFileEx);
|
|
var
|
|
I: Integer;
|
|
sCurrPlugin,
|
|
sValue: String;
|
|
begin
|
|
Ini.ReadSectionRaw('PackerPlugins', gWCXPlugins);
|
|
for I:= 0 to Count - 1 do
|
|
if Pos('#', Names[I]) = 0 then
|
|
begin
|
|
Enabled[I]:= True;
|
|
end
|
|
else
|
|
begin
|
|
sCurrPlugin:= Names[I];
|
|
sValue:= ValueFromIndex[I];
|
|
Self[I]:= Copy(sCurrPlugin, 2, Length(sCurrPlugin) - 1) + '=' + sValue;
|
|
Enabled[I]:= False;
|
|
end;
|
|
end;
|
|
|
|
procedure TWCXModuleList.Save(Ini: TIniFileEx);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Ini.EraseSection('PackerPlugins');
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
if Boolean(Objects[I]) then
|
|
begin
|
|
Ini.WriteString('PackerPlugins', Names[I], ValueFromIndex[I])
|
|
end
|
|
else
|
|
begin
|
|
Ini.WriteString('PackerPlugins', '#' + Names[I], ValueFromIndex[I]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TWCXModuleList.Add(Ext: String; Flags: PtrInt; FileName: String): Integer;
|
|
begin
|
|
Result:= AddObject(Ext + '=' + IntToStr(Flags) + #44 + FileName, TObject(True));
|
|
end;
|
|
|
|
end.
|