Ver Fonte

ADD: Zip - capability to change compression settings of all supported formats

Alexander Koblov há 2 anos atrás
pai
commit
8c46e8b089

+ 1 - 1
plugins/wcx/zip/src/Zip.dpr

@@ -7,7 +7,7 @@ uses
   FPCAdds,
   SysUtils,
   Classes,
-  ZipFunc in 'ZipFunc.pas';
+  ZipFunc, ZipOpt;
 
 exports
   { Mandatory }

+ 67 - 61
plugins/wcx/zip/src/ZipConfDlg.lfm

@@ -1,30 +1,30 @@
 object DialogBox: TDialogBox
-  Left = 518
-  Height = 325
-  Top = 108
-  Width = 455
+  Left = 693
+  Height = 353
+  Top = 345
+  Width = 438
   AutoSize = True
   BorderStyle = bsDialog
   Caption = 'Zip plugin configuration'
   ChildSizing.LeftRightSpacing = 10
   ChildSizing.TopBottomSpacing = 10
-  ClientHeight = 325
-  ClientWidth = 455
+  ClientHeight = 353
+  ClientWidth = 438
   OnShow = DialogBoxShow
   Position = poOwnerFormCenter
-  LCLVersion = '2.0.8.0'
+  LCLVersion = '2.2.4.0'
   object lblAbout: TLabel
     AnchorSideLeft.Control = Owner
     AnchorSideTop.Control = Owner
     AnchorSideRight.Control = gbCompression
     AnchorSideRight.Side = asrBottom
     Left = 10
-    Height = 72
+    Height = 57
     Top = 10
-    Width = 418
+    Width = 417
     Alignment = taCenter
     Anchors = [akTop, akLeft, akRight]
-    Caption = 'Zip plugin supports PKZIP-compatible, TAR, GZip and BZip2 data compression and archiving.'#10#10'Copyright (C) 2006-2020 Alexander Koblov ([email protected])'
+    Caption = 'Zip plugin supports PKZIP-compatible, TAR, XZ, GZip, Zstandard and BZip2 data compression and archiving.'
     ParentColor = False
     WordWrap = True
   end
@@ -33,9 +33,9 @@ object DialogBox: TDialogBox
     AnchorSideTop.Control = lblAbout
     AnchorSideTop.Side = asrBottom
     Left = 10
-    Height = 153
-    Top = 102
-    Width = 418
+    Height = 203
+    Top = 87
+    Width = 417
     AutoSize = True
     BorderSpacing.Top = 20
     Caption = 'Compression'
@@ -46,87 +46,93 @@ object DialogBox: TDialogBox
     ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
     ChildSizing.Layout = cclLeftToRightThenTopToBottom
     ChildSizing.ControlsPerLine = 2
-    ClientHeight = 126
-    ClientWidth = 412
+    ClientHeight = 183
+    ClientWidth = 415
     TabOrder = 0
-    object lblCompressionMethodToUse: TLabel
-      AnchorSideTop.Side = asrCenter
+    object lblArchiveFormat: TLabel
       Left = 10
-      Height = 26
+      Height = 35
       Top = 10
-      Width = 202
-      Caption = 'Compression method:'
+      Width = 204
+      Caption = 'Archive format:'
       Layout = tlCenter
       ParentColor = False
     end
-    object cbCompressionMethodToUse: TComboBox
-      AnchorSideRight.Side = asrBottom
-      Left = 237
-      Height = 26
+    object cbArchiveFormat: TComboBox
+      Left = 239
+      Height = 35
       Top = 10
-      Width = 165
-      ItemHeight = 18
-      ItemIndex = 2
-      Items.Strings = (
-        'Store'
-        'Deflate'
-        'Optimal (2x slower)'
-      )
+      Width = 166
+      ItemHeight = 0
       OnChange = ComboBoxChange
       Style = csDropDownList
       TabOrder = 0
     end
-    object lblDeflationOption: TLabel
+    object lblCompressionMethod: TLabel
       AnchorSideTop.Side = asrCenter
       Left = 10
-      Height = 26
-      Top = 41
-      Width = 202
+      Height = 35
+      Top = 50
+      Width = 204
+      Caption = 'Compression method:'
+      Layout = tlCenter
+      ParentColor = False
+    end
+    object cbCompressionMethod: TComboBox
+      AnchorSideRight.Side = asrBottom
+      Left = 239
+      Height = 35
+      Top = 50
+      Width = 166
+      ItemHeight = 0
+      OnChange = ComboBoxChange
+      Style = csDropDownList
+      TabOrder = 1
+    end
+    object lblCompressionLevel: TLabel
+      AnchorSideTop.Side = asrCenter
+      Left = 10
+      Height = 35
+      Top = 90
+      Width = 204
       Caption = 'Compression level:'
       Layout = tlCenter
       ParentColor = False
     end
-    object cbDeflationOption: TComboBox
+    object cbCompressionLevel: TComboBox
       AnchorSideLeft.Side = asrBottom
       AnchorSideTop.Side = asrBottom
       AnchorSideRight.Side = asrBottom
-      Left = 237
-      Height = 26
-      Top = 41
-      Width = 165
+      Left = 239
+      Height = 35
+      Top = 90
+      Width = 166
       BorderSpacing.Left = 20
-      ItemHeight = 18
-      ItemIndex = 0
-      Items.Strings = (
-        'Normal'
-        'Maximum'
-        'Fast'
-        'Fastest'
-      )
+      ItemHeight = 0
       OnChange = ComboBoxChange
       Style = csDropDownList
-      TabOrder = 1
+      TabOrder = 2
     end
     object chkTarAutoHandle: TCheckBox
       AnchorSideLeft.Control = gbCompression
-      AnchorSideTop.Control = cbDeflationOption
+      AnchorSideTop.Control = cbCompressionLevel
       AnchorSideTop.Side = asrBottom
       Left = 10
-      Height = 24
-      Top = 77
-      Width = 392
+      Height = 23
+      Top = 135
+      Width = 395
       BorderSpacing.Top = 10
       Caption = 'Open *.tar.xyz archives at one step (slowly with big archives)'
-      TabOrder = 2
+      TabOrder = 3
     end
   end
   object btnOK: TBitBtn
     AnchorSideTop.Control = btnCancel
     AnchorSideTop.Side = asrCenter
     AnchorSideRight.Control = btnCancel
-    Left = 218
-    Height = 29
-    Top = 275
+    Left = 217
+    Height = 36
+    Top = 310
     Width = 100
     Anchors = [akTop, akRight]
     AutoSize = True
@@ -144,9 +150,9 @@ object DialogBox: TDialogBox
     AnchorSideTop.Side = asrBottom
     AnchorSideRight.Control = gbCompression
     AnchorSideRight.Side = asrBottom
-    Left = 328
-    Height = 29
-    Top = 275
+    Left = 327
+    Height = 36
+    Top = 310
     Width = 100
     Anchors = [akTop, akRight]
     AutoSize = True

+ 177 - 74
plugins/wcx/zip/src/ZipConfDlg.pas

@@ -3,7 +3,7 @@
    -------------------------------------------------------------------------
    WCX plugin for working with *.zip, *.gz, *.bz2, *.tar, *.tgz, *.tbz archives
 
-   Copyright (C) 2008-2014 Alexander Koblov ([email protected])
+   Copyright (C) 2008-2023 Alexander Koblov ([email protected])
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
@@ -34,16 +34,161 @@ uses
   SysUtils, Extension;
 
 procedure CreateZipConfDlg;
-procedure LoadConfig;
-procedure SaveConfig;
-  
+
 implementation
 
-uses ZipFunc, AbZipTyp, DCClassesUtf8;
+uses
+  ZipFunc, ZipOpt, ZipLng, AbZipTyp;
+
+function GetComboBox(pDlg: PtrUInt; DlgItemName: PAnsiChar): PtrInt;
+var
+  Index: IntPtr;
+begin
+  with gStartupInfo do
+  begin
+    Index:= SendDlgMsg(pDlg, DlgItemName, DM_LISTGETITEMINDEX, 0, 0);
+    Result:= SendDlgMsg(pDlg, DlgItemName, DM_LISTGETDATA, Index, 0);
+  end;
+end;
+
+procedure SetComboBox(pDlg: PtrUInt; DlgItemName: PAnsiChar; ItemData: PtrInt);
+var
+  Index, Count: Integer;
+begin
+  with gStartupInfo do
+  begin
+    Count:= SendDlgMsg(pDlg, DlgItemName, DM_LISTGETCOUNT, 0, 0);
+    for Index:= 0 to Count - 1 do
+    begin
+      if SendDlgMsg(pDlg, DlgItemName, DM_LISTGETDATA, Index, 0) = ItemData then
+      begin
+        SendDlgMsg(pDlg, DlgItemName, DM_LISTSETITEMINDEX, Index, 0);
+        Exit;
+      end;
+    end;
+  end;
+end;
+
+function ComboBoxAdd(pDlg: PtrUInt; DlgItemName: PAnsiChar; ItemText: String; ItemData: PtrInt): IntPtr;
+var
+  P: PAnsiChar;
+  AText: IntPtr absolute P;
+begin
+  P:= PAnsiChar(ItemText);
+  Result:= gStartupInfo.SendDlgMsg(pDlg, DlgItemName, DM_LISTADD, AText, ItemData);
+end;
+
+function AddCompressionLevel(pDlg: PtrUInt; const AName: String; ALevel: IntPtr): IntPtr;
+var
+  AText: String;
+begin
+  AText:= AName + ' (' + IntToStr(ALevel) + ')';
+  Result:= ComboBoxAdd(pDlg, 'cbCompressionLevel', AText, ALevel);
+end;
+
+procedure UpdateLevel(pDlg: PtrUInt; ALevel: IntPtr);
+var
+  Index: IntPtr;
+  AFormat: TArchiveFormat;
+  AMethod: TAbZipCompressionMethod;
+begin
+  with gStartupInfo do
+  begin
+    SendDlgMsg(pDlg, 'cbCompressionLevel', DM_LISTCLEAR, 0, 0);
+    AFormat:= TArchiveFormat(GetComboBox(pDlg, 'cbArchiveFormat'));
+    Index:= SendDlgMsg(pDlg, 'cbCompressionMethod', DM_LISTGETITEMINDEX, 0, 0);
+    AMethod:= TAbZipCompressionMethod(SendDlgMsg(pDlg, 'cbCompressionMethod', DM_LISTGETDATA, Index, 0));
+    if (AMethod = cmStored) then
+    begin
+      SendDlgMsg(pDlg, 'cbCompressionLevel', DM_ENABLE, 0, 0);
+    end
+    else begin
+      SendDlgMsg(pDlg, 'cbCompressionLevel', DM_ENABLE, 1, 0);
+     case AMethod of
+       cmDeflated,
+       cmEnhancedDeflated:
+         begin
+          AddCompressionLevel(pDlg, rsCompressionLevelFastest, 1);
+          AddCompressionLevel(pDlg, rsCompressionLevelFast, 3);
+          Index:= AddCompressionLevel(pDlg, rsCompressionLevelNormal, 6);
+          AddCompressionLevel(pDlg, rsCompressionLevelMaximum, 9);
+         end;
+       cmXz,
+       cmLZMA,
+       cmBzip2:
+         begin
+          AddCompressionLevel(pDlg, rsCompressionLevelFastest, 1);
+          AddCompressionLevel(pDlg, rsCompressionLevelFast, 3);
+          Index:= AddCompressionLevel(pDlg, rsCompressionLevelNormal, 5);
+          AddCompressionLevel(pDlg, rsCompressionLevelMaximum, 7);
+          AddCompressionLevel(pDlg, rsCompressionLevelUltra, 9);
+         end;
+       cmZstd:
+         begin
+           AddCompressionLevel(pDlg, rsCompressionLevelFastest, 3);
+           AddCompressionLevel(pDlg, rsCompressionLevelFast, 5);
+           Index:= AddCompressionLevel(pDlg, rsCompressionLevelNormal, 11);
+           AddCompressionLevel(pDlg, rsCompressionLevelMaximum, 17);
+           AddCompressionLevel(pDlg, rsCompressionLevelUltra, 22);
+         end;
+     end;
+     if ALevel < 0 then
+       SendDlgMsg(pDlg, 'cbCompressionLevel', DM_LISTSETITEMINDEX, Index, 0)
+     else begin
+       SetComboBox(pDlg, 'cbCompressionLevel', PluginConfig[AFormat].Level);
+     end;
+    end;
+  end;
+end;
+
+procedure UpdateMethod(pDlg: PtrUInt);
+var
+  Index: IntPtr;
+  AFormat: TArchiveFormat;
+begin
+  with gStartupInfo do
+  begin
+    SendDlgMsg(pDlg, 'cbCompressionMethod', DM_LISTCLEAR, 0, 0);
+    AFormat:= TArchiveFormat(GetComboBox(pDlg, 'cbArchiveFormat'));
+    case AFormat of
+      afGzip:
+        ComboBoxAdd(pDlg, 'cbCompressionMethod', 'Deflate', PtrInt(cmDeflated));
+      afXzip:
+        ComboBoxAdd(pDlg, 'cbCompressionMethod', 'LZMA2', PtrInt(cmXz));
+      afBzip2:
+        ComboBoxAdd(pDlg, 'cbCompressionMethod', 'BZip2', PtrInt(cmBzip2));
+      afZstd:
+        ComboBoxAdd(pDlg, 'cbCompressionMethod', 'Zstandard', PtrInt(cmZstd));
+      afZip:
+        begin
+          ComboBoxAdd(pDlg, 'cbCompressionMethod', rsCompressionMethodStore, PtrInt(cmStored));
+          ComboBoxAdd(pDlg, 'cbCompressionMethod', 'Deflate', PtrInt(cmDeflated));
+          ComboBoxAdd(pDlg, 'cbCompressionMethod', rsCompressionMethodOptimal, PtrInt(cmEnhancedDeflated));
+        end;
+      afZipx:
+        begin
+          ComboBoxAdd(pDlg, 'cbCompressionMethod', 'LZMA2', PtrInt(cmXz));
+          ComboBoxAdd(pDlg, 'cbCompressionMethod', 'Zstandard', PtrInt(cmZstd));
+        end;
+    end; // case
+    Index:= SendDlgMsg(pDlg, 'cbCompressionMethod', DM_LISTGETCOUNT, 0, 0);
+    if (Index = 1) then
+    begin
+      SendDlgMsg(pDlg, 'cbCompressionMethod', DM_LISTSETITEMINDEX, 0, 0);
+      SendDlgMsg(pDlg, 'cbCompressionMethod', DM_ENABLE, 0, 0);
+    end
+    else begin
+      SendDlgMsg(pDlg, 'cbCompressionMethod', DM_ENABLE, 1, 0);
+      SetComboBox(pDlg, 'cbCompressionMethod', PluginConfig[AFormat].Method);
+    end;
+  end;
+  UpdateLevel(pDlg, PluginConfig[AFormat].Level);
+end;
 
 function DlgProc (pDlg: PtrUInt; DlgItemName: PAnsiChar; Msg, wParam, lParam: PtrInt): PtrInt; dcpcall;
 var
- iIndex: Integer;
+  Index: IntPtr;
+  AFormat: TArchiveFormat;
 begin
   Result:= 0;
   with gStartupInfo do
@@ -51,51 +196,38 @@ begin
     case Msg of
       DN_INITDIALOG:
         begin
-          case gCompressionMethodToUse of
-            smStored:
-              SendDlgMsg(pDlg, 'cbCompressionMethodToUse', DM_LISTSETITEMINDEX, 0, 0);
-            smDeflated:
-              SendDlgMsg(pDlg, 'cbCompressionMethodToUse', DM_LISTSETITEMINDEX, 1, 0);
-            smBestMethod:
-              SendDlgMsg(pDlg, 'cbCompressionMethodToUse', DM_LISTSETITEMINDEX, 2, 0);
-          end; // case
-          case gDeflationOption of
-            doNormal:
-              SendDlgMsg(pDlg, 'cbDeflationOption', DM_LISTSETITEMINDEX, 0, 0);
-            doMaximum:
-              SendDlgMsg(pDlg, 'cbDeflationOption', DM_LISTSETITEMINDEX, 1, 0);
-            doFast:
-              SendDlgMsg(pDlg, 'cbDeflationOption', DM_LISTSETITEMINDEX, 2, 0);
-            doSuperFast:
-              SendDlgMsg(pDlg, 'cbDeflationOption', DM_LISTSETITEMINDEX, 3, 0);
-          end; // case
+          ComboBoxAdd(pDlg, 'cbArchiveFormat', 'gz', PtrInt(afGzip));
+          ComboBoxAdd(pDlg, 'cbArchiveFormat', 'xz', PtrInt(afXzip));
+          ComboBoxAdd(pDlg, 'cbArchiveFormat', 'bz2', PtrInt(afBzip2));
+          ComboBoxAdd(pDlg, 'cbArchiveFormat', 'zst', PtrInt(afZstd));
+          Index:= ComboBoxAdd(pDlg, 'cbArchiveFormat', 'zip', PtrInt(afZip));
+          ComboBoxAdd(pDlg, 'cbArchiveFormat', 'zipx', PtrInt(afZipx));
+
+          SendDlgMsg(pDlg, 'cbArchiveFormat', DM_LISTSETITEMINDEX, Index, 0);
+
+          UpdateMethod(pDlg);
+
           SendDlgMsg(pDlg, 'chkTarAutoHandle', DM_SETCHECK, PtrInt(gTarAutoHandle), 0);
         end;
+      DN_CHANGE:
+        begin
+          if DlgItemName = 'cbArchiveFormat' then
+          begin
+            UpdateMethod(pDlg);
+          end
+          else if DlgItemName = 'cbCompressionMethod' then
+          begin
+            UpdateLevel(pDlg, -1);
+          end;
+        end;
       DN_CLICK:
         if DlgItemName = 'btnOK' then
           begin
-            iIndex:= SendDlgMsg(pDlg, 'cbCompressionMethodToUse', DM_LISTGETITEMINDEX, 0, 0);
-            case iIndex of
-              0:
-                gCompressionMethodToUse:= smStored;
-              1:
-                gCompressionMethodToUse:= smDeflated;
-              2:
-                gCompressionMethodToUse:= smBestMethod;
-            end; // case
-            iIndex:= SendDlgMsg(pDlg, 'cbDeflationOption', DM_LISTGETITEMINDEX, 0, 0);
-            case iIndex of
-              0:
-                gDeflationOption:= doNormal;
-              1:
-                gDeflationOption:= doMaximum;
-              2:
-                gDeflationOption:= doFast;
-              3:
-                gDeflationOption:= doSuperFast;
-            end; // case
+            AFormat:= TArchiveFormat(GetComboBox(pDlg, 'cbArchiveFormat'));
+            PluginConfig[AFormat].Level:= GetComboBox(pDlg, 'cbCompressionLevel');
+            PluginConfig[AFormat].Method:= GetComboBox(pDlg, 'cbCompressionMethod');
             gTarAutoHandle:= Boolean(SendDlgMsg(pDlg, 'chkTarAutoHandle', DM_GETCHECK, 0, 0));
-            SaveConfig;
+            SaveConfiguration;
             SendDlgMsg(pDlg, DlgItemName, DM_CLOSE, 1, 0);
           end
         else if DlgItemName = 'btnCancel' then
@@ -137,34 +269,5 @@ begin
   end;
 end;
 
-procedure LoadConfig;
-var
-  gIni: TIniFileEx;
-begin
-  gIni:= TIniFileEx.Create(gStartupInfo.PluginConfDir + IniFileName);
-  try
-    gCompressionMethodToUse:= TAbZipSupportedMethod(gIni.ReadInteger('Configuration', 'CompressionMethodToUse', Integer(smDeflated)));
-    gDeflationOption:= TAbZipDeflationOption(gIni.ReadInteger('Configuration', 'DeflationOption', Integer(AbDefDeflationOption)));
-    gTarAutoHandle:= gIni.ReadBool('Configuration', 'TarAutoHandle', True);
-  finally
-    gIni.Free;
-  end;
-end;
-
-procedure SaveConfig;
-var
-  gIni: TIniFileEx;
-begin
-  gIni:= TIniFileEx.Create(gStartupInfo.PluginConfDir + IniFileName);
-  try
-    gIni.WriteInteger('Configuration', 'CompressionMethodToUse', Integer(gCompressionMethodToUse));
-    gIni.WriteInteger('Configuration', 'DeflationOption', Integer(gDeflationOption));
-    gIni.WriteBool('Configuration', 'TarAutoHandle', gTarAutoHandle);
-    gIni.UpdateFile;
-  finally
-    gIni.Free;
-  end;
-end;
-
 end.
 

+ 38 - 11
plugins/wcx/zip/src/ZipFunc.pas

@@ -82,14 +82,12 @@ const
 
 var
   gStartupInfo: TExtensionStartupInfo;
-  gCompressionMethodToUse : TAbZipSupportedMethod;
-  gDeflationOption : TAbZipDeflationOption;
   gTarAutoHandle : Boolean;
   
 implementation
 
 uses
-  SysUtils, LazUTF8, ZipConfDlg, AbBrowse, DCConvertEncoding, DCOSUtils;
+  SysUtils, LazUTF8, ZipConfDlg, AbBrowse, DCConvertEncoding, DCOSUtils, ZipOpt;
 
 threadvar
   gProcessDataProcW : TProcessDataProcW;
@@ -332,11 +330,13 @@ end;
 
 function PackFilesW(PackedFile: PWideChar;  SubPath: PWideChar;  SrcPath: PWideChar;  AddList: PWideChar;  Flags: Integer): Integer;dcpcall;
 var
-  Arc : TAbZipKitEx;
+  FileExt: String;
   FilePath: String;
+  Arc : TAbZipKitEx;
   FileName: UnicodeString;
   sPassword: AnsiString;
   sPackedFile: String;
+  ArchiveFormat: TArchiveFormat;
 begin
   if (Flags and PK_PACK_MOVE_FILES) <> 0 then begin
     Exit(E_NOT_SUPPORTED);
@@ -346,23 +346,50 @@ begin
   try
     Arc.AutoSave := False;
     Arc.TarAutoHandle:= True;
-    Arc.CompressionMethodToUse:= gCompressionMethodToUse;
-    Arc.DeflationOption:= gDeflationOption;
     Arc.FProcessDataProcW := gProcessDataProcW;
     Arc.OnProcessItemFailure := @Arc.AbProcessItemFailureEvent;
 
     sPackedFile := UTF16ToUTF8(UnicodeString(PackedFile));
 
     try
-      if ((Flags and PK_PACK_ENCRYPT) <> 0) and
-         (LowerCase(ExtractFileExt(sPackedFile)) = '.zip') then // only zip supports encryption
+      FileExt:= LowerCase(ExtractFileExt(sPackedFile));
+
+      if ((Flags and PK_PACK_ENCRYPT) <> 0) then
       begin
-        Arc.AbNeedPasswordEvent(Arc, sPassword);
-        Arc.Password:= sPassword;
+        // Only zip/zipx supports encryption
+        if (FileExt = '.zip') or (FileExt = '.zipx') then
+        begin
+          sPassword:= EmptyStr;
+          Arc.AbNeedPasswordEvent(Arc, sPassword);
+          Arc.Password:= sPassword;
+        end;
       end;
 
       Arc.OpenArchive(sPackedFile);
 
+      ArchiveFormat:= ARCHIVE_FORMAT[Arc.ArchiveType];
+
+      if (ArchiveFormat = afZip) then
+      begin
+         if (FileExt = '.zipx') then
+           ArchiveFormat:= afZipx
+         else begin
+           case PluginConfig[ArchiveFormat].Level of
+             1: Arc.DeflationOption:= doSuperFast;
+             3: Arc.DeflationOption:= doFast;
+             6: Arc.DeflationOption:= doNormal;
+             9: Arc.DeflationOption:= doMaximum;
+           end;
+           case PluginConfig[ArchiveFormat].Method of
+              PtrInt(cmStored): Arc.CompressionMethodToUse:= smStored;
+              PtrInt(cmDeflated): Arc.CompressionMethodToUse:= smDeflated;
+              PtrInt(cmEnhancedDeflated): Arc.CompressionMethodToUse:= smBestMethod;
+           end;
+         end;
+      end;
+      Arc.ZipArchive.CompressionLevel:= PluginConfig[ArchiveFormat].Level;
+      Arc.ZipArchive.CompressionMethod:= PluginConfig[ArchiveFormat].Method;
+
       Arc.OnArchiveItemProgress := @Arc.AbArchiveItemProgressEvent;
       Arc.OnArchiveProgress := @Arc.AbArchiveProgressEvent;
       Arc.StoreOptions := Arc.StoreOptions + [soReplace];
@@ -481,7 +508,7 @@ procedure ExtensionInitialize(StartupInfo: PExtensionStartupInfo); dcpcall;
 begin
   gStartupInfo:= StartupInfo^;
   // Load configuration from ini file
-  LoadConfig;
+  LoadConfiguration;
 end;
 
 { TAbZipKitEx }

+ 45 - 0
plugins/wcx/zip/src/ZipLng.pas

@@ -0,0 +1,45 @@
+{
+  Double Commander
+  -------------------------------------------------------------------------
+  SevenZip archiver plugin, language support
+
+  Copyright (C) 2014-2015 Alexander Koblov ([email protected])
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+}
+
+unit ZipLng;
+
+{$mode delphi}
+
+interface
+
+uses
+  Classes, SysUtils;
+
+resourcestring
+  rsCompressionMethodStore = 'Store';
+  rsCompressionMethodOptimal = 'Optimal (2x slower)';
+
+  rsCompressionLevelFastest = 'Fastest';
+  rsCompressionLevelFast = 'Fast';
+  rsCompressionLevelNormal = 'Normal';
+  rsCompressionLevelMaximum = 'Maximum';
+  rsCompressionLevelUltra = 'Ultra';
+
+implementation
+
+end.
+

+ 128 - 0
plugins/wcx/zip/src/ZipOpt.pas

@@ -0,0 +1,128 @@
+unit ZipOpt;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, AbUtils, AbZipTyp;
+
+type
+  TArchiveFormat = (
+    afNil,
+    afZip,
+    afZipx,
+    afGzip,
+    afBzip2,
+    afXzip,
+    afLzma,
+    afZstd
+  );
+
+  TFormatOptions = record
+    Level: PtrInt;
+    Method: PtrInt;
+  end;
+
+const
+  ARCHIVE_FORMAT: array[TAbArchiveType] of TArchiveFormat =
+  (
+    afNil, afZip, afZip, afZip, afNil, afGzip, afGzip, afNil,
+    afBzip2, afBzip2, afXzip, afXzip, afLzma, afLzma, afZstd, afZstd
+  );
+
+const
+  DefaultConfig: array[TArchiveFormat] of TFormatOptions =
+  (
+   (Level: 0; Method: 0;),
+   (Level: 6; Method: PtrInt(cmDeflated);),
+   (Level: 7; Method: PtrInt(cmXz);),
+   (Level: 6; Method: PtrInt(cmDeflated);),
+   (Level: 9; Method: PtrInt(cmBzip2);),
+   (Level: 7; Method: PtrInt(cmXz);),
+   (Level: 7; Method: PtrInt(cmLZMA);),
+   (Level: 11; Method: PtrInt(cmZstd);)
+  );
+
+var
+  PluginConfig: array[TArchiveFormat] of TFormatOptions;
+
+procedure LoadConfiguration;
+procedure SaveConfiguration;
+
+implementation
+
+uses
+  TypInfo, DCClassesUtf8, Extension, ZipFunc;
+
+procedure LoadConfiguration;
+var
+  Ini: TIniFileEx;
+  Section: AnsiString;
+  ArchiveFormat: TArchiveFormat;
+begin
+  try
+    Ini:= TIniFileEx.Create(gStartupInfo.PluginConfDir + IniFileName);
+    try
+      for ArchiveFormat:= Succ(Low(TArchiveFormat)) to High(TArchiveFormat) do
+      begin
+        Section:= Copy(GetEnumName(TypeInfo(TArchiveFormat), PtrInt(ArchiveFormat)), 3, MaxInt);
+        PluginConfig[ArchiveFormat].Level:= Ini.ReadInteger(Section, 'Level', DefaultConfig[ArchiveFormat].Level);
+        PluginConfig[ArchiveFormat].Method:= Ini.ReadInteger(Section, 'Method', DefaultConfig[ArchiveFormat].Method);
+      end;
+      gTarAutoHandle:= Ini.ReadBool('Configuration', 'TarAutoHandle', True);
+      // Backward compatibility
+      case Ini.ReadInteger('Configuration', 'DeflationOption', -1) of
+        IntPtr(doSuperFast): PluginConfig[afZip].Level:= 1;
+        IntPtr(doFast): PluginConfig[afZip].Level:= 3;
+        IntPtr(doNormal): PluginConfig[afZip].Level:= 6;
+        IntPtr(doMaximum): PluginConfig[afZip].Level:= 9;
+      end;
+      case Ini.ReadInteger('Configuration', 'CompressionMethodToUse', -1) of
+        IntPtr(smStored): PluginConfig[afZip].Method:= IntPtr(cmStored);
+        IntPtr(smDeflated): PluginConfig[afZip].Method:= IntPtr(cmDeflated);
+        IntPtr(smBestMethod): PluginConfig[afZip].Method:= IntPtr(cmEnhancedDeflated);
+      end;
+    finally
+      Ini.Free;
+    end;
+  except
+    // Ignore
+  end;
+end;
+
+procedure SaveConfiguration;
+var
+  Ini: TIniFileEx;
+  Section: AnsiString;
+  ArchiveFormat: TArchiveFormat;
+begin
+  try
+    Ini:= TIniFileEx.Create(gStartupInfo.PluginConfDir + IniFileName);
+    try
+      for ArchiveFormat:= Succ(Low(TArchiveFormat)) to High(TArchiveFormat) do
+      begin
+        Section:= Copy(GetEnumName(TypeInfo(TArchiveFormat), PtrInt(ArchiveFormat)), 3, MaxInt);
+        Ini.WriteInteger(Section, 'Level', PluginConfig[ArchiveFormat].Level);
+        Ini.WriteInteger(Section, 'Method', PluginConfig[ArchiveFormat].Method);
+      end;
+      Ini.DeleteKey('Configuration', 'DeflationOption');
+      Ini.DeleteKey('Configuration', 'CompressionMethodToUse');
+      Ini.WriteBool('Configuration', 'TarAutoHandle', gTarAutoHandle);
+      Ini.UpdateFile;
+    finally
+      Ini.Free;
+    end;
+  except
+    on E: Exception do
+    begin
+      gStartupInfo.MessageBox(PAnsiChar(E.Message), nil, MB_OK or MB_ICONERROR);
+    end;
+  end;
+end;
+
+initialization
+  Move(DefaultConfig[Low(DefaultConfig)], PluginConfig[Low(PluginConfig)], SizeOf(PluginConfig));
+
+end.
+

+ 8 - 0
plugins/wcx/zip/src/fparchive/abarctyp.pas

@@ -292,6 +292,8 @@ type
     FInStream       : TStream;
     FIsDirty        : Boolean;
     FSpanningThreshold      : Int64;
+    FCompressionLevel       : IntPtr;
+    FCompressionMethod      : IntPtr;
     FItemList       : TAbArchiveList;
     FLogFile        : string;
     FLogging        : Boolean;
@@ -495,6 +497,12 @@ type
     property TempDirectory : string
       read FTempDir
       write FTempDir;
+    property CompressionLevel: IntPtr
+      read FCompressionLevel
+      write FCompressionLevel;
+    property CompressionMethod: IntPtr
+      read FCompressionMethod
+      write FCompressionMethod;
 
   public {events}
     property OnProcessItemFailure : TAbArchiveItemFailureEvent

+ 3 - 8
plugins/wcx/zip/src/fparchive/abbzip2.pas

@@ -114,14 +114,11 @@ type
   indicator when you are writing a large chunk of data to the compression
   stream in a single call.}
 
-
-  TBlockSize100k = (bs1, bs2, bs3, bs4, bs5, bs6, bs7, bs8, bs9);
-
   TBZCompressionStream = class(TCustomBZip2Stream)
   private
     function GetCompressionRate: Single;
   public
-    constructor Create(BlockSize100k: TBlockSize100k; Dest: TStream);
+    constructor Create(Level: IntPtr; Dest: TStream);
     destructor Destroy; override;
     function Read(var Buffer; Count: Longint): Longint; override;
     function Write(const Buffer; Count: Longint): Longint; override;
@@ -605,15 +602,13 @@ end; { TCustomBZip2Stream }
 
 // TBZCompressionStream
 
-constructor TBZCompressionStream.Create(BlockSize100k: TBlockSize100k; Dest: TStream);
-const
-  BlockSizes: array[TBlockSize100k] of ShortInt = (1, 2, 3, 4, 5, 6, 7, 8, 9);
+constructor TBZCompressionStream.Create(Level: IntPtr; Dest: TStream);
 begin
   inherited Create(Dest);
   LoadBzip2DLL;
   FBZRec.next_out := @FBuffer[0];
   FBZRec.avail_out := sizeof(FBuffer);
-  CCheck(BZ2_bzCompressInit(FBZRec, BlockSizes[BlockSize100k], 0, 0));
+  CCheck(BZ2_bzCompressInit(FBZRec, Level, 0, 0));
 end;
 
 destructor TBZCompressionStream.Destroy;

+ 2 - 2
plugins/wcx/zip/src/fparchive/abbzip2typ.pas

@@ -341,7 +341,7 @@ begin
       FBzip2Stream := TAbProgressFileStream.Create(TempFileName, fmCreate or fmShareDenyWrite, OnProgress);
     end;
     FTarStream.Position := 0;
-    CompStream := TBZCompressionStream.Create(bs9, FBzip2Stream);
+    CompStream := TBZCompressionStream.Create(CompressionLevel, FBzip2Stream);
     try
       CompStream.CopyFrom(FTarStream, 0);
     finally
@@ -372,7 +372,7 @@ begin
         aaDelete: ; {doing nothing omits file from new stream}
         aaAdd, aaFreshen, aaReplace, aaStreamAdd: begin
           FBzip2Stream.Size := 0;
-          CompStream := TBZCompressionStream.Create(bs9, FBzip2Stream);
+          CompStream := TBZCompressionStream.Create(CompressionLevel, FBzip2Stream);
           try
             if CurItem.Action = aaStreamAdd then
               CompStream.CopyFrom(InStream, 0){ Copy/compress entire Instream to FBzip2Stream }

+ 20 - 6
plugins/wcx/zip/src/fparchive/abgztyp.pas

@@ -197,10 +197,12 @@ type
     function GetGzCRC: LongInt;
     function GetFileSize: LongInt;
   protected {private}
-    FItem : TAbGzipItem;
-    FTail : TAbGzTailRec;
+    FItem    : TAbGzipItem;
+    FTail    : TAbGzTailRec;
+    FArchive : TAbArchive;
   public
-    constructor Create(AStream : TStream);
+    constructor Create(AStream : TStream); overload;
+    constructor Create(Archive : TAbArchive; AStream : TStream); overload;
     destructor Destroy; override;
 
     procedure ExtractItemData(AStream : TStream); override;
@@ -464,12 +466,18 @@ end;
 
 { TAbGzipStreamHelper }
 
-constructor TAbGzipStreamHelper.Create(AStream : TStream);
+constructor TAbGzipStreamHelper.Create(AStream: TStream);
 begin
   inherited Create(AStream);
   FItem := TAbGzipItem.Create;
 end;
 
+constructor TAbGzipStreamHelper.Create(Archive : TAbArchive; AStream: TStream);
+begin
+  Create(AStream);
+  FArchive := Archive;
+end;
+
 destructor TAbGzipStreamHelper.Destroy;
 begin
   FItem.Free;
@@ -575,6 +583,12 @@ var
 begin
   Helper := TAbDeflateHelper.Create;
   try
+    case FArchive.CompressionLevel of
+      1 : Helper.PKZipOption := 's';
+      3 : Helper.PKZipOption := 'f';
+      6 : Helper.PKZipOption := 'n';
+      9 : Helper.PKZipOption := 'x';
+    end;
     FItem.CRC32 := Deflate(AStream, FStream, Helper);
     FItem.UncompressedSize := AStream.Size;
   finally
@@ -1138,7 +1152,7 @@ begin
   NewStream := nil;
 
   try
-    InGzHelp := TAbGzipStreamHelper.Create(FGzStream);
+    InGzHelp := TAbGzipStreamHelper.Create(Self, FGzStream);
 
     try
       {init new archive stream}
@@ -1149,7 +1163,7 @@ begin
         ATempName := GetTempName(FArchiveName);
         NewStream := TFileStreamEx.Create(ATempName, fmCreate or fmShareDenyWrite);
       end;
-      OutGzHelp := TAbGzipStreamHelper.Create(NewStream);
+      OutGzHelp := TAbGzipStreamHelper.Create(Self, NewStream);
 
       { save the Tar data }
       if IsGzippedTar and TarAutoHandle then begin

+ 3 - 3
plugins/wcx/zip/src/fparchive/abxz.pas

@@ -103,7 +103,7 @@ type
   protected
     function Check(Return: cint): cint; override;
   public
-    constructor Create(ASource, ATarget: TStream); override;
+    constructor Create(ASource, ATarget: TStream; ALevel: Integer);
     function Code(Count: cuint64 = High(cuint64)): Boolean; override;
   end;
 
@@ -232,10 +232,10 @@ begin
   end;
 end;
 
-constructor TLzmaCompression.Create(ASource, ATarget: TStream);
+constructor TLzmaCompression.Create(ASource, ATarget: TStream; ALevel: Integer);
 begin
   inherited Create(ASource, ATarget);
-  Check(lzma_easy_encoder(FLzmaRec, 6, LZMA_CHECK_CRC64));
+  Check(lzma_easy_encoder(FLzmaRec, ALevel, LZMA_CHECK_CRC64));
 end;
 
 function TLzmaCompression.Code(Count: cuint64): Boolean;

+ 3 - 3
plugins/wcx/zip/src/fparchive/abxztyp.pas

@@ -333,7 +333,7 @@ begin
       FXzStream := TAbProgressFileStream.Create(TempFileName, fmCreate or fmShareDenyWrite, OnProgress);
     end;
     FTarStream.Position := 0;
-    LzmaCompression := TLzmaCompression.Create(FTarStream, FXzStream);
+    LzmaCompression := TLzmaCompression.Create(FTarStream, FXzStream, FCompressionLevel);
     try
       LzmaCompression.Code();
     finally
@@ -366,7 +366,7 @@ begin
           FXzStream.Size := 0;
           if CurItem.Action = aaStreamAdd then
           begin
-            LzmaCompression := TLzmaCompression.Create(InStream, FXzStream);
+            LzmaCompression := TLzmaCompression.Create(InStream, FXzStream, FCompressionLevel);
             try
               LzmaCompression.Code(); { Copy/compress entire Instream to FXzStream }
             finally
@@ -376,7 +376,7 @@ begin
           else begin
             InputFileStream := TAbProgressFileStream.Create(CurItem.DiskFileName, fmOpenRead or fmShareDenyWrite, OnProgress);
             try
-              LzmaCompression := TLzmaCompression.Create(InputFileStream, FXzStream);
+              LzmaCompression := TLzmaCompression.Create(InputFileStream, FXzStream, FCompressionLevel);
               try
                 LzmaCompression.Code(); { Copy/compress entire Instream to FXzStream }
               finally

+ 8 - 2
plugins/wcx/zip/src/fparchive/abzipprc.pas

@@ -62,7 +62,7 @@ uses
   AbVMStrm,
   AbDfBase,
   AbZlibPrc,
-  AbXzPrc,
+  AbZipxPrc,
   DCClassesUtf8;
 
 
@@ -210,7 +210,13 @@ begin
     if InStream.Size > 0 then begin
 
       if SameText(ExtractFileExt(Sender.ArchiveName), '.zipx') then
-        DoCompressXz(ZipArchive, Item, DestStrm, InStream)
+      begin
+        case ZipArchive.CompressionMethod of
+          IntPtr(cmXz):   DoCompressXz(ZipArchive, Item, DestStrm, InStream);
+          IntPtr(cmZstd): DoCompressZstd(ZipArchive, Item, DestStrm, InStream);
+          else raise Exception.Create(EmptyStr);
+        end;
+      end
       else
       { determine how to store Item based on specified CompressionMethodToUse }
       case ZipArchive.CompressionMethodToUse of

+ 27 - 4
plugins/wcx/zip/src/fparchive/abxzprc.pas → plugins/wcx/zip/src/fparchive/abzipxprc.pas

@@ -25,12 +25,12 @@
  * ***** END LICENSE BLOCK ***** *)
 
 {**********************************************************}
-{* ABBREVIA: AbXzPrc.pas                                  *}
+{* ABBREVIA: AbZipxPrc.pas                                *}
 {**********************************************************}
 {* ABBREVIA: TZipHashStream class                         *}
 {**********************************************************}
 
-unit AbXzPrc;
+unit AbZipxPrc;
 
 {$mode delphi}
 
@@ -56,11 +56,12 @@ type
   end;
 
 procedure DoCompressXz(Archive : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream);
+procedure DoCompressZstd(Archive : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream);
 
 implementation
 
 uses
-  AbXz, AbExcept, DCcrc32;
+  AbXz, AbZstd, AbExcept, DCcrc32;
 
 procedure DoCompressXz(Archive : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream);
 var
@@ -71,7 +72,7 @@ begin
   ASource := TZipHashStream.Create(InStream);
   try
     ASource.OnProgress := Archive.OnProgress;
-    LzmaCompression := TLzmaCompression.Create(ASource, OutStream);
+    LzmaCompression := TLzmaCompression.Create(ASource, OutStream, Archive.CompressionLevel);
     try
       LzmaCompression.Code(Item.UncompressedSize);
     finally
@@ -83,6 +84,28 @@ begin
   end;
 end;
 
+procedure DoCompressZstd(Archive: TAbZipArchive; Item: TAbZipItem; OutStream,
+  InStream: TStream);
+var
+  ASource: TZipHashStream;
+  CompStream: TZSTDCompressionStream;
+begin
+  Item.CompressionMethod := cmZstd;
+  ASource := TZipHashStream.Create(InStream);
+  try
+    ASource.OnProgress := Archive.OnProgress;
+    CompStream := TZSTDCompressionStream.Create(OutStream, Archive.CompressionLevel, Item.UncompressedSize);
+    try
+      CompStream.CopyFrom(ASource, Item.UncompressedSize);
+    finally
+      CompStream.Free;
+    end;
+    Item.CRC32 := not ASource.Hash;
+  finally
+    ASource.Free;
+  end;
+end;
+
 { TZipHashStream }
 
 constructor TZipHashStream.Create(ASource: TStream);

+ 1 - 0
sdk/extension.h

@@ -41,6 +41,7 @@
 #define DM_SETPROGRESSVALUE DM_FIRST+37
 #define DM_SETPROGRESSSTYLE DM_FIRST+38
 #define DM_SETPASSWORDCHAR DM_FIRST+39
+#define DM_LISTCLEAR DM_FIRST+40
 
 /* events messages */
 #define DN_FIRST 0x1000

+ 1 - 0
sdk/extension.pas

@@ -44,6 +44,7 @@ const
   DM_SETPROGRESSVALUE     = DM_FIRST+37;
   DM_SETPROGRESSSTYLE     = DM_FIRST+38;
   DM_SETPASSWORDCHAR      = DM_FIRST+39;
+  DM_LISTCLEAR            = DM_FIRST+40;
 
   // events messages
   DN_FIRST                = $1000;

+ 9 - 0
src/fdialogbox.pas

@@ -388,6 +388,15 @@ begin
       else if Control is TMemo then
         TMemo(Control).Lines[wParam]:= AText;
     end;
+  DM_LISTCLEAR:
+    begin
+      if Control is TComboBox then
+        TComboBox(Control).Clear
+      else if Control is TListBox then
+        TListBox(Control).Clear
+      else if Control is TMemo then
+        TMemo(Control).Clear;
+    end;
   DM_GETTEXT:
     begin
       with DialogBox do