Subversion Repositories autosfx

Rev

Blame | Last modification | View Log | RSS feed

  1. unit ZMDllOpr19;
  2.  
  3. (*
  4.   ZMDllOpr19.pas - Dll operations and functions
  5.     Copyright (C) 2009, 2010  by Russell J. Peters, Roger Aelbrecht,
  6.       Eric W. Engler and Chris Vleghert.
  7.  
  8.         This file is part of TZipMaster Version 1.9.
  9.  
  10.     TZipMaster is free software: you can redistribute it and/or modify
  11.     it under the terms of the GNU Lesser General Public License as published by
  12.     the Free Software Foundation, either version 3 of the License, or
  13.     (at your option) any later version.
  14.  
  15.     TZipMaster is distributed in the hope that it will be useful,
  16.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.     GNU Lesser General Public License for more details.
  19.  
  20.     You should have received a copy of the GNU Lesser General Public License
  21.     along with TZipMaster.  If not, see <http://www.gnu.org/licenses/>.
  22.  
  23.     contact: problems@delphizip.org (include ZipMaster in the subject).
  24.     updates: http://www.delphizip.org
  25.     DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip
  26.  
  27.   modified 2010-02-10
  28.   --------------------------------------------------------------------------- *)
  29.  
  30. interface
  31.  
  32. {$INCLUDE '.\ZipVers19.inc'}
  33.  
  34. uses
  35.   Classes, Windows, Controls, Graphics, Dialogs,
  36.   ZMDelZip19, ZipMstr19, ZMCompat19, ZMWrkr19, ZMCore19;
  37.  
  38. // {$DEFINE ZDEBUG}
  39.  
  40. type
  41.   TZMDLLOpr = class;
  42.  
  43.   TDZCallback = class
  44.   private
  45.     fHoldSize: Integer;
  46.     PCB: PZCallBackStruct;
  47.     function GetActionCode: Integer;
  48.     function GetArg1: Cardinal;
  49.     function GetArg2: Cardinal;
  50.     function GetArg3: Integer;
  51.     function GetFile_Size: Int64;
  52.     function GetIsZip: Boolean;
  53.     function GetMsg: TZMString;
  54.     function GetMsg2: TZMString;
  55.     function GetOwner: TZMDLLOpr;
  56.     function GetWritten: Int64;
  57.     procedure SetArg1(const Value: Cardinal);
  58.     procedure SetArg2(const Value: Cardinal);
  59.     procedure SetArg3(const Value: Integer);
  60.     procedure SetFile_Size(const Value: Int64);
  61.     procedure SetMsg(const Value: TZMString);
  62.   protected
  63.     fHeldData: PByte;
  64.     fWorker: TZMWorker;
  65.     function Assign(ZCallBackRec: PZCallBackStruct): Integer;
  66.     function CopyData(dst: PByte; MaxSize: Integer): Boolean;
  67.     function HoldData(const src: PByte; size: Cardinal): PByte;
  68.     function HoldString(const src: TZMString): PByte;
  69.     function GetMsgStr(const msg: PByte): TZMString;
  70.     procedure SetComment(const AStr: AnsiString);
  71.     procedure SetData(src: PByte; size: Integer);
  72.   public
  73.     constructor Create(theWorker: TZMWorker);
  74.     destructor Destroy; override;
  75.     procedure Clear;
  76.     property ActionCode: Integer Read GetActionCode;
  77.     property Arg1: Cardinal Read GetArg1 Write SetArg1;
  78.     property Arg2: Cardinal Read GetArg2 Write SetArg2;
  79.     property Arg3: Integer Read GetArg3 Write SetArg3;
  80.     property File_Size: Int64 Read GetFile_Size Write SetFile_Size;
  81.     property IsZip: Boolean Read GetIsZip;
  82.     property msg: TZMString read GetMsg write SetMsg;
  83.     property Msg2: TZMString read GetMsg2;
  84.     property Owner: TZMDLLOpr Read GetOwner;
  85.     property Written: Int64 Read GetWritten;
  86.   end;
  87.  
  88.   // type
  89.   TZMDLLOpr = class(TZMWorker)
  90.   private
  91.     fAddCompLevel: Integer;
  92.     fAddStoreSuffixes: TZMAddStoreExts;
  93.     fAutoAttr: Cardinal;
  94.     fAutoDate: Cardinal;
  95.     fCB: TDZCallback;
  96.     fDidLoad: Boolean;
  97.     fDLLDirectory: string;
  98.     fDLLOperKey: Cardinal;
  99.     fDLLTargetName: String;
  100.     fEncrypt: Boolean;
  101.     fExtAddStoreSuffixes: String;
  102.     fExtrBaseDir: String;
  103.     fExtrOptions: TZMExtrOpts;
  104.     fFromDate: TDate;
  105.     // 1 data for dll held until next callback or fini
  106.     fHeldData: Pointer;
  107.     fPassword: String;
  108.     FPasswordReqCount: Integer;
  109.     FPipes: TZMPipeListImp;
  110.     fRootDir: String;
  111.     fZipStream: TMemoryStream;
  112.     function DLLStreamClose(ZStreamRec: PZStreamRec): Integer;
  113.     function DLLStreamCreate(ZStreamRec: PZStreamRec): Integer;
  114.     function DLLStreamIdentify(ZStreamRec: PZStreamRec): Integer;
  115.     function DllToErrCode(DLL_error: Integer): integer;
  116.     procedure DLL_Comment(var Result: Integer);
  117.     procedure DLL_CRCError(var Result: Integer);
  118.     procedure DLL_Data(var Result: Integer);
  119.     procedure DLL_ExtName(var Result: Integer);
  120.     procedure DLL_Message(var Result: Integer);
  121.     procedure DLL_Overwrite(var Result: Integer);
  122.     procedure DLL_Password(var Result: Integer);
  123.     procedure DLL_Progress(Action: TActionCodes; var Result: Integer);
  124.     procedure DLL_SetAddName(var Result: Integer);
  125.     procedure DLL_Skipped(var Result: Integer);
  126.     function GetDLL_Build: Integer;
  127.     function GetDLL_Load: Boolean;
  128.     function GetDLL_Path: string;
  129.     procedure GrabPipes;
  130.     procedure SetCB(const Value: TDZCallback);
  131.     procedure SetDLL_Load(const Value: Boolean);
  132.     procedure SetExtAddStoreSuffixes(const Value: String);
  133.     procedure SetPipes(const Value: TZMPipeListImp);
  134.   protected
  135.     fAutoStream: TStream;
  136.     function AddStoreExtStr(Options: TZMAddStoreExts): String;
  137.     function AllocDLLCommand(const FileName: String): pDLLCommands;
  138.     procedure DestroyDLLCmd(var rec: pDLLCommands);
  139.     function DLLCallback(ZCallBackRec: PZCallBackStruct): Integer;
  140.     function DLLStreamOp(op: TZStreamActions; ZStreamRec: PZStreamRec): Integer;
  141.     procedure DLL_Arg(var Result: Integer);
  142.     procedure ExtAdd;
  143.     procedure ExtExtract;
  144.     function SetupUnzCmd(const Value: String): pDLLCommands;
  145.     function SetupZipCmd(const Value: String): pDLLCommands;
  146.     property DLLTargetName: String read fDLLTargetName write fDLLTargetName;
  147.   public
  148.     constructor Create(AMaster: TCustomZipMaster19);
  149.     procedure AbortDLL;
  150.     function Add: Integer;
  151.     procedure AddStreamToFile(const FileName: String;
  152.       FileDate, FileAttr: Dword);
  153.     procedure AddStreamToStream(InStream: TMemoryStream);
  154.     procedure AfterConstruction; override;
  155.     procedure BeforeDestruction; override;
  156.     procedure Clear; override;
  157.     procedure Deflate(OutStream, InStream: TStream; Length: Int64; var Method:
  158.         TZMDeflates; var crc: Cardinal); override;
  159.     function DLL_Version(Load: Boolean): string;
  160.     procedure Done(Good: boolean = true); override;
  161.     procedure Extract;
  162.     procedure ExtractFileToStream(const FileName: String);
  163.     procedure ExtractStreamToStream(InStream: TMemoryStream; OutSize: Longword);
  164.     function GetAddPassword(var Response: TmsgDlgBtn): String;
  165.     function GetExtrPassword(var Response: TmsgDlgBtn): String;
  166.     function GetPassword(const DialogCaption, MsgTxt: String; ctx: Integer;
  167.       pwb: TmsgDlgButtons; var ResultStr: String): TmsgDlgBtn; overload;
  168.     function GetPassword(const DialogCaption, MsgTxt: String;
  169.       pwb: TmsgDlgButtons; var ResultStr: String): TmsgDlgBtn; overload;
  170.     procedure Kill; override;
  171.     procedure StartUp; override;
  172.     procedure Undeflate(OutStream, InStream: TStream; Length: Int64; var Method:
  173.         tzMDeflates; var crc: Cardinal); override;
  174.     property AddCompLevel: Integer Read fAddCompLevel Write fAddCompLevel;
  175.     property AddStoreSuffixes
  176.       : TZMAddStoreExts Read fAddStoreSuffixes Write fAddStoreSuffixes;
  177.     property CB: TDZCallback Read fCB Write SetCB;
  178.     property DLLDirectory: string read fDLLDirectory write fDLLDirectory;
  179.     property DLL_Build: Integer read GetDLL_Build;
  180.     property DLL_Load: Boolean read GetDLL_Load write SetDLL_Load;
  181.     property DLL_Path: string read GetDLL_Path;
  182.     property Encrypt: Boolean Read fEncrypt Write fEncrypt;
  183.     property ExtAddStoreSuffixes: String Read fExtAddStoreSuffixes Write
  184.       SetExtAddStoreSuffixes;
  185.     property ExtrBaseDir: String Read fExtrBaseDir Write fExtrBaseDir;
  186.     property ExtrOptions: TZMExtrOpts Read fExtrOptions Write fExtrOptions;
  187.     property FromDate: TDate Read fFromDate Write fFromDate;
  188.     property Password: String Read fPassword Write fPassword;
  189.     property PasswordReqCount: Integer read FPasswordReqCount write
  190.         FPasswordReqCount;
  191.     property Pipes: TZMPipeListImp read FPipes write SetPipes;
  192.     property RootDir: String Read fRootDir Write fRootDir;
  193.     property ZipStream: TMemoryStream Read fZipStream;
  194.   end;
  195.  
  196. implementation
  197.  
  198. uses
  199.   SysUtils, Forms, ZMMsg19, ZMXcpt19, ZMUtils19, ZMMsgStr19, ZMCtx19,
  200.   ZMDlg19, ZMZipFile19, ZMCenDir19, ZMDrv19, ZMStructs19, ZMUTF819,
  201.   ZMDLLLoad19, ZMIRec19;
  202.  
  203. (* ? ZCallback
  204.   1.76 01 May 2004 RP change return type and value to return flag for exception
  205.   1.76 24 April 2004 RP use DLLCallback
  206.   1.73 ( 1 June 2003) changed for new callback
  207.   { Dennis Passmore (Compuserve: 71640,2464) contributed the idea of passing an
  208.   instance handle to the DLL, and, in turn, getting it back from the callback.
  209.   This lets us referance variables in the TZMDLLOpr class from within the
  210.   callback function.  Way to go Dennis!
  211.   Modified by Russell Peters }
  212. *)
  213. function ZCallback(ZCallBackRec: PZCallBackStruct): Longint; stdcall;
  214. begin
  215.   Result := CALLBACK_ERROR;
  216.   if ZCallBackRec^.Check = ZCallBack_Check then
  217.   begin
  218.     with TObject(ZCallBackRec^.Caller) as TZMDLLOpr do
  219.       Result := DLLCallback(ZCallBackRec);
  220.   end;
  221. end;
  222.  
  223. function ZStreamCallback(ZStreamRec: PZStreamRec): Longint; stdcall;
  224. var
  225.   cnt: Integer;
  226.   op: TZStreamActions;
  227.   Strm: TStream;
  228. begin
  229.   Result := CALLBACK_ERROR;
  230.   try
  231.     if ZStreamRec^.Check = ZStream_Check then
  232.     begin
  233.       with ZStreamRec^ do
  234.       begin
  235.         op := TZStreamActions(OpCode);
  236.         Result := 0;
  237.         case op of
  238.           zsaIdentify .. zsaClose:
  239.             with TObject(ZStreamRec^.Caller) as TZMDLLOpr do
  240.               Result := DLLStreamOp(op, ZStreamRec);
  241.           zsaPosition: // reposition
  242.             begin
  243. {$IFNDEF VERD6up}
  244.               if Integer(ArgLL) <> ArgLL then
  245.                 raise EZipMaster.CreateResDisp(DS_SeekError, true);
  246. {$ENDIF}
  247.               Strm := TObject(StrmP) as TStream;
  248.               ArgLL := Strm.Seek(ArgLL, ArgI);
  249.               if ArgLL >= 0 then
  250.                 Result := CALLBACK_TRUE;
  251.             end;
  252.           zsaRead: // read
  253.             begin
  254.               Strm := TObject(StrmP) as TStream;
  255.               cnt := ArgI;
  256.               if (Strm.Position + cnt) > Strm.size then
  257.                 cnt := Integer(Strm.size - Strm.Position);
  258.               ArgI := Strm.Read(BufP^, cnt);
  259.               if ArgI = cnt then
  260.                 Result := CALLBACK_TRUE;
  261.             end;
  262.           zsaWrite: // Write
  263.             begin
  264.               Strm := TObject(StrmP) as TStream;
  265.               cnt := ArgI;
  266.               ArgI := Strm.Write(BufP^, cnt);
  267.               if ArgI = cnt then
  268.                 Result := CALLBACK_TRUE;
  269.             end;
  270.         end;
  271.       end;
  272.     end;
  273.   except
  274.     on E: Exception do
  275.     begin
  276.       // clear any exceptions
  277.       Result := CALLBACK_ERROR;
  278.     end;
  279.   end;
  280. end;
  281.  
  282. constructor TZMDLLOpr.Create(AMaster: TCustomZipMaster19);
  283. begin
  284.   inherited Create(AMaster);
  285. end;
  286.  
  287. procedure TZMDLLOpr.AbortDLL;
  288. begin
  289.   if fDLLOperKey <> 0 then
  290.     _DLL_Abort(self, fDLLOperKey);
  291. end;
  292.  
  293. (* ? TZMDLLOpr.Add
  294. *)
  295. function TZMDLLOpr.Add: Integer;
  296. begin
  297.   fAutoStream := nil;
  298.   ExtAdd;
  299.   Result := ErrCode;
  300. end;
  301.  
  302. (* ? TZMDLLOpr.AddStoreExtStr
  303. *)
  304. function TZMDLLOpr.AddStoreExtStr(Options: TZMAddStoreExts): String;
  305. const
  306.   SuffixStrings: array [TZMAddStoreSuffixEnum] of PChar =
  307.     ('gif', 'png', 'z', 'zip', 'zoo', 'arc', 'lzh', 'arj', 'taz', 'tgz', 'lha',
  308.     'rar', 'ace', 'cab', 'gz', 'gzip', 'jar', 'exe', '', 'jpg', 'jpeg', '7zp',
  309.     'mp3', 'wmv', 'wma', 'dvr-ms', 'avi');
  310. var
  311.   o: TZMAddStoreSuffixEnum;
  312. begin
  313.   for o := Low(TZMAddStoreSuffixEnum) to High(TZMAddStoreSuffixEnum) do
  314.     if (o <> assEXT) and (o in Options) then
  315.       Result := Result + '.' + String(SuffixStrings[o]) + ':';
  316.   if assEXT in Options then
  317.     Result := Result + fExtAddStoreSuffixes;
  318. end;
  319.  
  320. (* ? TZMDLLOpr.AddStreamToFile
  321.   // EWE: I think 'FileName' is the name you want to use in the zip file to
  322.   // store the contents of the stream under.
  323. *)
  324. procedure TZMDLLOpr.AddStreamToFile(const FileName: String;
  325.   FileDate, FileAttr: Dword);
  326. var
  327.   FatDate: Word;
  328.   FatTime: Word;
  329.   fn: String;
  330.   ft: TFileTime;
  331.   st: TSystemTime;
  332. begin
  333.   fn := Trim(FileName);
  334.   if (Length(FileName) = 0) and (FSpecArgs.Count > 0) then
  335.     fn := Trim(FSpecArgs[0]);
  336.   if (fn = '') or (ZipStream.size = 0) then
  337.   begin
  338.     ShowZipMessage(AD_NothingToZip, '');
  339.     exit;
  340.   end;
  341.   if IsWild(fn) then
  342.   begin
  343.     ShowZipMessage(AD_InvalidName, '');
  344.     exit;
  345.   end;
  346.   FSpecArgs.Clear();
  347.  
  348.   FSpecArgs.Add('0:' + fn);
  349.   if FileDate = 0 then
  350.   begin
  351.     GetLocalTime(st);
  352.     SystemTimeToFileTime(st, ft);
  353.     FileTimeToDosDateTime(ft, FatDate, FatTime);
  354.     FileDate := (Dword(FatDate) shl 16) + FatTime;
  355.   end;
  356.   SuccessCnt := 0;
  357.   fAutoStream := ZipStream;
  358.   fAutoDate := FileDate;
  359.   fAutoAttr := FileAttr;
  360.   // Add;
  361.   ExtAdd;
  362. end;
  363.  
  364. (* ? TZMDLLOpr.AddStreamToStream
  365. *)
  366. procedure TZMDLLOpr.AddStreamToStream(InStream: TMemoryStream);
  367. var
  368.   Header: TZM_StreamHeader;
  369.   Method: TZMDeflates;
  370. begin
  371.   SuccessCnt := 0;
  372.   if InStream = ZipStream then
  373.   begin
  374.     ShowZipMessage(AD_InIsOutStream, '');
  375.     exit;
  376.   end;
  377.   if assigned(InStream) and (InStream.size > 0) then
  378.   begin
  379.     if AddEncrypt in AddOptions then
  380.     begin
  381.       ShowZipMessage(DS_NoEncrypt, '');
  382.       exit;
  383.     end;
  384.     ZipStream.size := 0;
  385.     Method := zmDeflate;
  386.     Header.Method := METHOD_DEFLATED;
  387.     Header.CRC := 0;
  388.     ZipStream.WriteBuffer(Header, SizeOf(Header));
  389.     Deflate(ZipStream, InStream, -1, Method, Header.CRC);
  390.     if SuccessCnt = 1 then
  391.     begin
  392.       ZipStream.Position := 0;
  393.       if Method <> zmDeflate then
  394.         Header.Method := METHOD_STORED; // was stored
  395.       ZipStream.WriteBuffer(Header, SizeOf(Header));
  396.     end
  397.     else
  398.       ZipStream.size := 0;
  399.   end
  400.   else
  401.     ShowZipMessage(AD_NothingToZip, '');
  402. end;
  403.  
  404. procedure TZMDLLOpr.AfterConstruction;
  405. begin
  406.   inherited;
  407.   fDLLOperKey := 0;
  408.   fHeldData := nil;
  409.   fPassword := '';
  410.   fPasswordReqCount := 1;
  411.   fEncrypt := False;
  412.   fAddCompLevel := 9; // dflt to tightest compression
  413.   fAddStoreSuffixes := ZMDefAddStoreSuffixes;
  414.   fZipStream := TMemoryStream.Create;
  415.   fCB := TDZCallback.Create(self);
  416.   FPipes := TZMPipeListImp.Create;
  417. end;
  418.  
  419. function TZMDLLOpr.AllocDLLCommand(const FileName: String): pDLLCommands;
  420. var
  421.   Opts: Cardinal;
  422. begin
  423.   Result := AllocMem(SizeOf(TDLLCommands));
  424.   DLLTargetName := FileName;
  425.   ZeroMemory(Result, SizeOf(TDLLCommands));
  426.   Result^.fVersion := DELZIPVERSION; // version we expect the DLL to be
  427.   Result^.fCaller := self; // point to our VCL instance; returned in Report
  428.  
  429.   Result^.ZCallbackFunc := ZCallback; // pass addr of function to be called from DLL
  430.   Result^.ZStreamFunc := ZStreamCallback;
  431.   Result^.fEncodedAs := Ord(Encoding); // how to interpret existing names
  432.   Result^.fFromPage := Encoding_CP;
  433.  
  434.   if Verbosity >= zvTrace then
  435.     Result^.fVerbosity := -1
  436.   else if Verbosity >= zvVerbose then
  437.     Result^.fVerbosity := 1
  438.   else
  439.     Result^.fVerbosity := 0;
  440.   { if tracing, we want verbose also }
  441.  
  442.   // used for dialogs (like the pwd dialogs)
  443.   if Unattended then
  444.     Result^.fHandle := 0
  445.   else
  446.     Result^.fHandle := Handle;
  447.   Result^.fSS := nil;
  448.  
  449.   Opts := DLL_OPT_Quiet; // no DLL error reporting
  450.  
  451.   Result^.fOptions := Opts;
  452. end;
  453.  
  454. procedure TZMDLLOpr.BeforeDestruction;
  455. begin
  456.   fIsDestructing := true; // stop callbacks
  457.   AbortDLL;
  458.   if fHeldData <> nil then
  459.     FreeMem(fHeldData); // release held data
  460.   FreeAndNil(fZipStream);
  461.   FreeAndNil(fCB);
  462.   FPipes.Clear;
  463.   FreeAndNil(FPipes);
  464.   _DLL_Remove(self); // remove from list
  465.   inherited;
  466. end;
  467.  
  468. procedure TZMDLLOpr.Clear;
  469. begin
  470.   fIsDestructing := true; // stop callbacks
  471.   AbortDLL;
  472.   fIsDestructing := False; // restore callbacks
  473.   inherited;
  474.   fPassword := '';
  475.   fPasswordReqCount := 1;
  476.   fEncrypt := False;
  477.   fAddCompLevel := 9; // dflt to tightest compression
  478.   fAddStoreSuffixes := ZMDefAddStoreSuffixes;
  479.   fZipStream.size := 0;
  480.   FPipes.Clear;
  481. end;
  482.  
  483. procedure TZMDLLOpr.Deflate(OutStream, InStream: TStream; Length: Int64; var
  484.     Method: TZMDeflates; var crc: Cardinal);
  485. var
  486.   Args: TZSSArgs;
  487.   CmdRecP: pDLLCommands;
  488.   i: Integer;
  489.   ncrypt: boolean;
  490. begin
  491.   SuccessCnt := 0;
  492.   ClearErr;
  493.   if not assigned(InStream) then
  494.   begin
  495.     ShowZipMessage(DS_NoInStream, '');
  496.     exit;
  497.   end;
  498.   if not assigned(OutStream) then
  499.   begin
  500.     ShowZipMessage(DS_NoOutStream, '');
  501.     exit;
  502.   end;
  503.   if InStream = ZipStream then
  504.   begin
  505.     ShowZipMessage(AD_InIsOutStream, '');
  506.     exit;
  507.   end;
  508.   CmdRecP := nil;
  509.   ncrypt := (Method = zmStoreEncrypt) or (Method = zmDeflateEncrypt);
  510.   // We can not do an Unattended Add if we don't have a password.
  511.   if Unattended and ncrypt and (Password = '') then
  512.   begin
  513.     ShowZipMessage(AD_UnattPassword, '');
  514.     exit;
  515.   end;
  516.   if Length < 0 then
  517.     Length := InStream.size;
  518.   if (Method = zmDeflate) or (Method = zmDeflateEncrypt) then
  519.     Args.Method := 8
  520.   else
  521.     Args.Method := 0;
  522.   Args.fSSInput := InStream;
  523.   Args.fSSOutput := OutStream;
  524.   Args.size := Length;
  525.   Args.crc := crc;
  526.   if _DLL_Load(self) <= 0 then
  527.   begin
  528.     ShowZipMessage(LD_NoDLL, DelZipDLL_Name);
  529.     exit;
  530.   end;
  531.   try
  532.     if ncrypt then
  533.       AddOptions := AddOptions + [addEncrypt]
  534.     else
  535.       AddOptions := AddOptions - [addEncrypt];
  536.     CmdRecP := SetupZipCmd('');
  537.     CmdRecP^.fSS := @Args;
  538.     fEventErr := ''; // added
  539.     { pass in a ptr to parms }
  540.     i := _DLL_Exec(self, CmdRecP, fDLLOperKey);
  541.   finally
  542.     _DLL_Unload(self);
  543.     DestroyDLLCmd(CmdRecP);
  544.   end;
  545.   if i = 1 then
  546.   begin // success
  547.     SuccessCnt := 1;
  548.     if Args.Method = 8 then
  549.       Method := zmDeflate
  550.     else
  551.       Method := zmStore;
  552.     crc := Args.crc;
  553.   end;
  554. end;
  555.  
  556. procedure TZMDLLOpr.DestroyDLLCmd(var rec: pDLLCommands);
  557. begin
  558.   if rec <> nil then
  559.   begin
  560.     FreeMem(rec);
  561.     rec := nil;
  562.   end;
  563. end;
  564.  
  565. (* ? TZMDLLOpr.DLLCallback
  566. *)
  567. function TZMDLLOpr.DLLCallback(ZCallBackRec: PZCallBackStruct): Integer;
  568. var
  569.   Action: TActionCodes;
  570. begin
  571.   Result := CALLBACK_UNHANDLED; // unhandled //CALLBACK_IGNORED;
  572.   if fIsDestructing then // in destructor return
  573.   begin
  574.     exit;
  575.   end;
  576.   CB.Assign(ZCallBackRec);
  577.   Action := TActionCodes(CB.ActionCode and 63);
  578.   try
  579.     case Action of
  580.       zacMessage:
  581.         DLL_Message(Result);
  582.       zacItem .. zacXProgress:
  583.         DLL_Progress(Action, Result);
  584.       zacNewName:
  585.         // request for a new path+name just before zipping or extracting
  586.         DLL_SetAddName(Result);
  587.       zacPassword:
  588.         // New or other password needed during Extract()
  589.         DLL_Password(Result);
  590.       zacCRCError:
  591.         // CRC32 error, (default action is extract/test the file)
  592.         DLL_CRCError(Result);
  593.       zacOverwrite:
  594.         // Extract(UnZip) Overwrite ask
  595.         DLL_Overwrite(Result);
  596.       zacSkipped:
  597.         // Extract(UnZip) and Skipped
  598.         DLL_Skipped(Result);
  599.       zacComment:
  600.         // Add(Zip) FileComments.
  601.         DLL_Comment(Result);
  602.       zacData:
  603.         // Set Extra Data
  604.         DLL_Data(Result);
  605.       zacExtName:
  606.         // request for a new path+name just before zipping or extracting
  607.         DLL_ExtName(Result);
  608.       zacKey:
  609.         begin
  610.           fDLLOperKey := CB.Arg1;
  611.           Result := 0;
  612.         end;
  613.       zacArg:
  614.         DLL_Arg(Result);
  615.     else
  616.       Result := CALLBACK_IGNORED; // unknown
  617.     end; { end case }
  618.     if (Action < zacKey) and (Action > zacMessage) then
  619.     begin
  620.       KeepAlive;
  621.     end;
  622.     if Cancel <> 0 then
  623.     begin
  624.       Result := CALLBACK_CANCEL;
  625.       if Sniffer <> 0 then
  626.         ReportToSniffer(0, '[CANCEL sent]');
  627.     end;
  628.   except
  629.     on E: Exception do
  630.     begin
  631.       if fEventErr = '' then
  632.         // catch first exception only
  633.         fEventErr := ' #' + IntToStr(Ord(Action)) + ' "' + E.Message + '"';
  634.       Cancel := GE_Except;
  635.       Result := CALLBACK_EXCEPTION;
  636.       if Sniffer <> 0 then
  637.         ReportToSniffer(0, '[CALLBACK Exception sent] ' + fEventErr);
  638.     end;
  639.   end;
  640. end;
  641.  
  642. function TZMDLLOpr.DLLStreamClose(ZStreamRec: PZStreamRec): Integer;
  643. var
  644.   IsDone: Boolean;
  645.   SNumber: Integer;
  646.   Strm: TStream;
  647.   tmpOnStream: TZMStreamEvent;
  648.   zstats: TZMSStats;
  649. begin
  650.   zstats.size := 0;
  651.   zstats.Date := 0;
  652.   zstats.Attrs := 0;
  653.   Result := CALLBACK_UNHANDLED;
  654.   if TObject(ZStreamRec^.StrmP) is TStream then
  655.   begin
  656.     Strm := TStream(ZStreamRec^.StrmP);
  657.     if Strm = ZipStream then
  658.     begin
  659.       fAutoStream := nil;
  660.       ZStreamRec^.StrmP := nil;
  661.       Result := CALLBACK_TRUE;
  662.     end
  663.     else
  664.     begin
  665.           IsDone := False;
  666.       tmpOnStream := Master.OnStream;
  667.       SNumber := ZStreamRec^.Number;
  668.       if assigned(tmpOnStream) then
  669.       begin
  670.         if (Strm <> ZipStream) then
  671.         begin
  672.           tmpOnStream(Master, zsoClose, SNumber, Strm, zstats, IsDone);
  673.           if IsDone then
  674.           begin
  675.             Result := CALLBACK_TRUE;
  676.             ZStreamRec^.StrmP := Strm;
  677.           end;
  678.         end;
  679.       end;
  680.     if (not IsDone) and FPipes.HasStream(SNumber) then
  681.       begin
  682.         FPipes.KillStream(SNumber);
  683.         Result := CALLBACK_TRUE;
  684.       end;
  685.     end;
  686.   end;
  687. end;
  688.  
  689. function TZMDLLOpr.DLLStreamCreate(ZStreamRec: PZStreamRec): Integer;
  690. var
  691.   IsDone: Boolean;
  692.   pipe: TZMPipe;
  693.   SNumber: Integer;
  694.   Strm: TStream;
  695.   tmpOnStream: TZMStreamEvent;
  696.   zstats: TZMSStats;
  697. begin
  698.   zstats.size := 0;
  699.   zstats.Date := 0;
  700.   zstats.Attrs := 0;
  701.   Result := CALLBACK_UNHANDLED;
  702.   ZStreamRec^.StrmP := nil;
  703.   if assigned(fAutoStream) then
  704.   begin
  705.     Result := CALLBACK_TRUE;
  706.     ZStreamRec^.StrmP := fAutoStream;
  707.     fAutoStream.Position := 0;
  708.   end
  709.   else
  710.   begin
  711.     IsDone := False;
  712.     tmpOnStream := Master.OnStream;
  713.     SNumber := ZStreamRec^.Number;
  714.     if assigned(tmpOnStream) then
  715.     begin
  716.       IsDone := False;
  717.       tmpOnStream(Master, zsoOpen, SNumber, Strm, zstats, IsDone);
  718.       if IsDone and assigned(Strm) then
  719.       begin
  720.         Result := CALLBACK_TRUE;
  721.         ZStreamRec^.StrmP := Strm;
  722.       end;
  723.     end;
  724.     if (not IsDone) and FPipes.HasStream(SNumber) then
  725.     begin
  726.       pipe := FPipes[SNumber];
  727.       Result := CALLBACK_TRUE;
  728.       ZStreamRec^.StrmP := pipe.Stream;
  729.     end;
  730.   end;
  731. end;
  732.  
  733. function TZMDLLOpr.DLLStreamIdentify(ZStreamRec: PZStreamRec): Integer;
  734. var
  735.   IsDone: Boolean;
  736.   pipe: TZMPipe;
  737.   SNumber: Integer;
  738.   Strm: TStream;
  739.   tmpOnStream: TZMStreamEvent;
  740.   zstats: TZMSStats;
  741. begin
  742.   zstats.size := 0;
  743.   zstats.Date := 0;
  744.   zstats.Attrs := 0;
  745.   Result := CALLBACK_UNHANDLED;
  746.   if assigned(fAutoStream) then
  747.   begin
  748.     Result := CALLBACK_TRUE;
  749.     ZStreamRec^.ArgLL := fAutoStream.size;
  750.     ZStreamRec^.ArgD := fAutoDate;
  751.     ZStreamRec^.ArgA := fAutoAttr;
  752.   end
  753.   else
  754.   begin
  755.       IsDone := False;
  756.     tmpOnStream := Master.OnStream;
  757.     SNumber := ZStreamRec^.Number;
  758.     if assigned(tmpOnStream) then
  759.     begin
  760.       tmpOnStream(Master, zsoIdentify, SNumber, Strm, zstats, IsDone);
  761.       if IsDone then
  762.       begin
  763.         Result := CALLBACK_TRUE;
  764.         ZStreamRec^.ArgLL := zstats.size;
  765.         ZStreamRec^.ArgD := zstats.Date;
  766.         ZStreamRec^.ArgA := zstats.Attrs;
  767.       end;
  768.     end;
  769.     if (not IsDone) and FPipes.HasStream(SNumber) then
  770.     begin
  771.       pipe := FPipes[SNumber];
  772.       Result := CALLBACK_TRUE;
  773.       ZStreamRec^.ArgLL := pipe.size;
  774.       ZStreamRec^.ArgD := pipe.DOSDate;
  775.       ZStreamRec^.ArgA := pipe.Attributes;
  776.     end;
  777.   end;
  778. end;
  779.  
  780. // ALL interface structures BYTE ALIGNED
  781. (* stream operation arg usage
  782.   zacStIdentify,
  783.   //      IN BufP = name
  784.   IN Number = number
  785.   OUT ArgLL = size, ArgD = Date, ArgA = Attrs
  786.   zacStCreate,
  787.   //      IN BufP = name
  788.   IN Number = number
  789.   OUT StrmP = stream
  790.   zacStClose,
  791.   IN Number = number
  792.   IN StrmP = stream
  793.   OUT StrmP = stream (= NULL)
  794.   zacStPosition,
  795.   IN Number = number
  796.   IN StrmP = stream, ArgLL = offset, ArgI = from
  797.   OUT ArgLL = position
  798.   zacStRead,
  799.   IN Number = number
  800.   IN StrmP = stream, BufP = buf, ArgI = count
  801.   OUT ArgI = bytes read
  802.   zacStWrite
  803.   IN Number = number
  804.   IN StrmP = stream, BufP = buf, ArgI = count
  805.   OUT ArgI = bytes written
  806. *)
  807. function TZMDLLOpr.DLLStreamOp(op: TZStreamActions; ZStreamRec: PZStreamRec)
  808.   : Integer;
  809. begin
  810.   Result := CALLBACK_UNHANDLED;
  811.   case op of
  812.     zsaIdentify: // get details for named stream
  813.         Result := DLLStreamIdentify(ZStreamRec);
  814.     zsaCreate: // Assign a stream
  815.         Result := DLLStreamCreate(ZStreamRec);
  816.     zsaClose: // defaults to freeing stream if not ZipStream
  817.         Result := DLLStreamClose(ZStreamRec);
  818.   end;
  819.   if Verbosity >= zvVerbose then
  820.   begin
  821.     Diag(Format('Stream operation %d on %d returns %d',
  822.         [Ord(op), ZStreamRec^.Number, Result]));
  823.   end;
  824. end;
  825.  
  826. // return proper ErrCode for dll error
  827. function TZMDLLOpr.DllToErrCode(DLL_error: Integer): integer;
  828. begin
  829.   Result := DLL_error and 255;
  830.   if Result <> 0 then
  831.     Result := DZ_RES_GOOD + Result;
  832.   if Result > DZ_ERR_DUPNAME then
  833.     Result := DZ_RES_ERROR;
  834. end;
  835.  
  836. (* Arg1 = argument
  837.   0 = filename
  838.   1 = password
  839.   2 = RootDir
  840.   3 = ExtractDir
  841.   4 = Zip comment
  842.   5 = FSpecArgs      Arg3 = index
  843.   6 = FSpecArgsExcl  Arg3 = index
  844. *)
  845. procedure TZMDLLOpr.DLL_Arg(var Result: Integer);
  846. var
  847.   Arg: TCBArgs;
  848.   idx: Integer;
  849.   sr: TZMString;
  850. begin
  851.   if CB.Arg1 <= Cardinal(Ord( HIGH(TCBArgs))) then
  852.   begin
  853.     Arg := TCBArgs(CB.Arg1);
  854.     idx := CB.Arg3;
  855.     sr := '';
  856.     if (Arg in [zcbFSpecArgs, zcbFSpecArgsExcl]) and (idx < 0) then
  857.       Result := CALLBACK_ERROR
  858.     else if Arg = zcbComment then
  859.     begin // always Ansi
  860.       CB.SetComment(ZipComment);
  861.       Result := CALLBACK_TRUE;
  862.     end
  863.     else
  864.     begin
  865.       Result := CALLBACK_TRUE;
  866.       case Arg of
  867.         zcbFilename:
  868.           sr := DLLTargetName;
  869.         zcbPassword:
  870.           sr := Password;
  871.         zcbRootDir:
  872.           sr := RootDir;
  873.         zcbExtractDir:
  874.           sr := ExtrBaseDir;
  875.         zcbFSpecArgs:
  876.           begin
  877.             if idx >= FSpecArgs.Count then
  878.               Result := CALLBACK_UNHANDLED
  879.             else
  880.               sr := FSpecArgs[idx];
  881.             CB.Arg3 := FSpecArgs.Count;
  882.           end;
  883.         zcbFSpecArgsExcl:
  884.           begin
  885.             if idx >= FSpecArgsExcl.Count then
  886.               Result := CALLBACK_UNHANDLED
  887.             else
  888.               sr := FSpecArgsExcl[idx];
  889.             CB.Arg3 := FSpecArgsExcl.Count;
  890.           end;
  891.         zcbSpecials:
  892.           sr := AddStoreExtStr(AddStoreSuffixes);
  893.         zcbTempPath:
  894.           sr := TempDir;
  895.       end;
  896.       CB.msg := sr;
  897.     end;
  898.   end
  899.   else
  900.     Result := CALLBACK_ERROR;
  901. end;
  902.  
  903. procedure TZMDLLOpr.DLL_Comment(var Result: Integer);
  904. var
  905.   FileComment: TZMString;
  906.   IsChanged: Boolean;
  907.   ti: Integer;
  908.   tmpFileComment: TZMFileCommentEvent;
  909. begin
  910.   tmpFileComment := Master.OnFileComment;
  911.   if assigned(tmpFileComment) then
  912.   begin
  913.     FileComment := CB.Msg2;
  914.     IsChanged := False;
  915.     tmpFileComment(Master, CB.msg, FileComment, IsChanged);
  916.     if IsChanged then
  917.     begin
  918.       Result := CALLBACK_TRUE;
  919.       ti := Length(FileComment);
  920.       if ti > 255 then
  921.       begin
  922.         ti := 255;
  923.         FileComment := Copy(FileComment, 1, 255);
  924.       end;
  925.       CB.msg := FileComment;
  926.       CB.Arg1 := ti;
  927.     end;
  928.   end;
  929.   if (Cancel <> 0) and (Result >= CALLBACK_IGNORED) then
  930.     Result := CALLBACK_CANCEL;
  931. end;
  932.  
  933. procedure TZMDLLOpr.DLL_CRCError(var Result: Integer);
  934. var
  935.   DoExtract: Boolean;
  936.   tmpCRC32Error: TZMCRC32ErrorEvent;
  937. begin
  938.   DoExtract := true;
  939.   tmpCRC32Error := Master.OnCRC32Error;
  940.   if assigned(tmpCRC32Error) then
  941.   begin
  942.     tmpCRC32Error(Master, CB.msg, CB.Arg1, CB.Arg2, DoExtract);
  943.     if DoExtract then
  944.       Result := CALLBACK_TRUE
  945.     else
  946.       Result := CALLBACK_3;
  947.   end;
  948. end;
  949.  
  950. procedure TZMDLLOpr.DLL_Data(var Result: Integer);
  951. var
  952.   dat: TZMRawBytes;
  953.   DataChanged: Boolean;
  954.   DatSize: Int64;
  955.   IsChanged: Boolean;
  956.   LevelChanged: Boolean;
  957.   lvl: Integer;
  958.   tmpFileExtra: TZMFileExtraEvent;
  959.   tmpSetCompLevel: TZMSetCompLevel;
  960.   xlen: Integer;
  961. begin
  962.   tmpFileExtra := Master.OnFileExtra;
  963.   tmpSetCompLevel := Master.OnSetCompLevel;
  964.   LevelChanged := False;
  965.   DataChanged := False;
  966.   if assigned(tmpSetCompLevel) then
  967.   begin
  968.     IsChanged := False;
  969.     lvl := Integer(CB.Arg2);
  970.     tmpSetCompLevel(Master, CB.msg, lvl, IsChanged);
  971.     if IsChanged and (lvl in [0 .. 9]) then
  972.     begin
  973.       CB.Arg2 := lvl;
  974.       LevelChanged := true;
  975.     end;
  976.   end;
  977.   if assigned(tmpFileExtra) then
  978.   begin
  979.     DatSize := CB.Arg1; // old size
  980.     SetLength(dat, DatSize);
  981.     if DatSize > 0 then
  982.       CB.CopyData(PByte(@dat[1]), DatSize);
  983.     IsChanged := False;
  984.     tmpFileExtra(Master, CB.msg, dat, IsChanged);
  985.     if IsChanged then
  986.     begin
  987.       DataChanged := true;
  988.       xlen := Length(dat);
  989.       if xlen > 2047 then // limit
  990.         xlen := 2047;
  991.       CB.SetData(PByte(@dat[1]), xlen);
  992.     end;
  993.   end;
  994.   if DataChanged then
  995.   begin
  996.     if LevelChanged then
  997.       Result := CALLBACK_3
  998.     else
  999.       Result := CALLBACK_TRUE;
  1000.   end
  1001.   else
  1002.   begin
  1003.     if LevelChanged then
  1004.       Result := CALLBACK_2;
  1005.   end;
  1006. end;
  1007.  
  1008. procedure TZMDLLOpr.DLL_ExtName(var Result: Integer);
  1009. var
  1010.   BaseDir: TZMString;
  1011.   IsChanged: Boolean;
  1012.   msg: TZMString;
  1013.   OldFileName: TZMString;
  1014.   tmpSetExtName: TZMSetExtNameEvent;
  1015.  
  1016.   function IsPathOnly(const f: String): Boolean;
  1017.   var
  1018.     c: Char;
  1019.   begin
  1020.     Result := False;
  1021.     if f <> '' then
  1022.     begin
  1023.       c := f[Length(f)];
  1024.       if (c = PathDelim) or (c = PathDelimAlt) then
  1025.         Result := true;
  1026.     end;
  1027.   end;
  1028.  
  1029. begin
  1030.   tmpSetExtName := Master.OnSetExtName;
  1031.   if assigned(tmpSetExtName) then
  1032.   begin
  1033.     msg := CB.Msg2;
  1034.     BaseDir := SetSlashW(msg, psdExternal);
  1035.     msg := CB.msg;
  1036.     OldFileName := msg;
  1037.     IsChanged := False;
  1038.     tmpSetExtName(Master, OldFileName, BaseDir, IsChanged);
  1039.     if IsChanged and (OldFileName <> msg) and
  1040.       (IsPathOnly(OldFileName) = IsPathOnly(msg)) then
  1041.     begin
  1042.       CB.msg := OldFileName;
  1043.       Result := CALLBACK_TRUE;
  1044.     end;
  1045.   end;
  1046. end;
  1047.  
  1048. procedure TZMDLLOpr.DLL_Message(var Result: Integer);
  1049. var
  1050.   ECode: Integer;
  1051.   Erm: TZMString;
  1052.   ErrorCode: Integer;
  1053.   EType: Integer;
  1054. begin
  1055.   Erm := CB.msg;
  1056.   ErrorCode := CB.Arg1;
  1057.   if (ErrorCode > 0) and (DllErrCode = 0) then
  1058.     DllErrCode := ErrorCode;   // remember last error
  1059.   ECode := DllToErrCode(ErrorCode);
  1060.   EType := ErrorCode and DZM_Type_Mask;
  1061.   if (EType >= DZM_Message) and ((ErrorCode and DZM_MessageBit) <> 0) then
  1062.     Erm := ZipLoadStr(ECode) + Erm;
  1063.   if (ECode <> 0) and (ErrCode = 0) then // W'll always keep the last ErrorCode
  1064.   begin
  1065.     if (fEventErr <> '') and (ECode = _DZ_ERR_ABORT) then
  1066.     begin
  1067.       Erm := ZipFmtLoadStr(GE_EventEx, [fEventErr]);
  1068.     end;
  1069.   end;
  1070.   if Sniffer <> 0 then
  1071.     ReportToSniffer(ErrorCode, Erm);
  1072.   ReportMessage1(ECode, Erm);
  1073. end;
  1074.  
  1075. procedure TZMDLLOpr.DLL_Overwrite(var Result: Integer);
  1076. var
  1077.   DoOverwrite: Boolean;
  1078.   tmpExtractOverwrite: TZMExtractOverwriteEvent;
  1079. begin
  1080.   tmpExtractOverwrite := Master.OnExtractOverwrite;
  1081.   if assigned(tmpExtractOverwrite) then
  1082.   begin
  1083.     DoOverwrite := CB.Arg1 <> 0;
  1084.     tmpExtractOverwrite(Master, CB.msg, CB.Arg3 <> 2, DoOverwrite, CB.Arg2);
  1085.     if DoOverwrite then
  1086.       Result := CALLBACK_TRUE
  1087.     else
  1088.       Result := CALLBACK_2;
  1089.     if Sniffer <> 0 then
  1090.       ReportToSniffer
  1091.         (0, Format('[Overwrite] IN=%d,%d OUT=%d', [CB.Arg1, CB.Arg2, Result]));
  1092.   end;
  1093. end;
  1094.  
  1095. procedure TZMDLLOpr.DLL_Password(var Result: Integer);
  1096. var
  1097.   IsZip: Boolean;
  1098.   pwd: String;
  1099.   Response: TmsgDlgBtn;
  1100.   RptCount: Longword;
  1101.   tmpPasswordError: TZMPasswordErrorEvent;
  1102. begin
  1103.   pwd := '';
  1104.   RptCount := CB.Arg1;
  1105.   Response := mbOK;
  1106.   IsZip := CB.IsZip;
  1107.   tmpPasswordError := Master.OnPasswordError;
  1108.   if assigned(tmpPasswordError) then
  1109.   begin
  1110.     tmpPasswordError(Master, IsZip, pwd, CB.msg, RptCount, Response);
  1111.     if Response <> mbOK then
  1112.       pwd := '';
  1113.   end
  1114.   else if IsZip then
  1115.     pwd := GetAddPassword(Response)
  1116.   else
  1117.     pwd := GetExtrPassword(Response);
  1118.  
  1119.   if pwd <> '' then
  1120.   begin
  1121.     CB.msg := pwd;
  1122.     Result := CALLBACK_TRUE;
  1123.   end
  1124.   else
  1125.   begin // no password
  1126.     RptCount := 0;
  1127.     Result := CALLBACK_2;
  1128.   end;
  1129.   if RptCount > 15 then
  1130.     RptCount := 15;
  1131.   CB.Arg1 := RptCount;
  1132.   if Response = mbCancel then // Cancel
  1133.   begin
  1134.     Result := CALLBACK_2;
  1135.   end
  1136.   else if Response = mbNoToAll then // Cancel all
  1137.   begin
  1138.     Result := CALLBACK_3;
  1139.   end
  1140.   else if Response = mbAbort then // Abort
  1141.   begin
  1142.     Cancel := GE_Abort;
  1143.     Result := CALLBACK_ABORT;
  1144.   end;
  1145. end;
  1146.  
  1147. procedure TZMDLLOpr.DLL_Progress(Action: TActionCodes; var Result: Integer);
  1148. var
  1149.   ErrorCode: Integer;
  1150.   File_Size: Int64;
  1151.   M: String;
  1152. begin
  1153.   ErrorCode := 0;
  1154.   File_Size := 0;
  1155.   M := '';
  1156.   if (Action > zacTick) and (Action <= zacXProgress) then
  1157.     File_Size := CB.File_Size;
  1158. //    File_Size := Int64(CB.File_Size);
  1159.   if (Action = zacItem) or (Action = zacXItem) then
  1160.     M := CB.msg;
  1161.   case Action of
  1162.     zacItem .. zacEndOfBatch:
  1163.         ProgDetail.Written(CB.Written);
  1164. //        ProgDetail.Written(Int64(CB.Written));
  1165.     zacCount:
  1166.       File_Size := CB.Arg1;
  1167.     zacXItem, zacXProgress:
  1168.         ErrorCode := CB.Arg1;
  1169.   end;
  1170.   ReportProgress(Action, ErrorCode, M, File_Size);
  1171.   Result := 0;
  1172. end;
  1173.  
  1174. procedure TZMDLLOpr.DLL_SetAddName(var Result: Integer);
  1175. var
  1176.   IsChanged: Boolean;
  1177.   M: String;
  1178.   M2: String;
  1179.   OldFileName: TZMString;
  1180.   OrigName: TZMString;
  1181.   tmpSetAddName: TZMSetAddNameEvent;
  1182. begin
  1183.   tmpSetAddName := Master.OnSetAddName;
  1184.   if assigned(tmpSetAddName) then
  1185.   begin
  1186.     M := CB.msg; // saves OldFileName
  1187.     M2 := CB.Msg2;
  1188.     if assigned(tmpSetAddName) then
  1189.     begin
  1190.       OrigName := SetSlashW(M2, psdExternal);
  1191.       OldFileName := M;
  1192.       IsChanged := False;
  1193.  
  1194.       tmpSetAddName(Master, OldFileName, OrigName, IsChanged);
  1195.       if IsChanged then
  1196.       begin
  1197.         CB.msg := OldFileName;
  1198.         Result := CALLBACK_TRUE;
  1199.       end;
  1200.     end;
  1201.   end;
  1202. end;
  1203.  
  1204. procedure TZMDLLOpr.DLL_Skipped(var Result: Integer);
  1205. var
  1206.   ErrorCode: Integer;
  1207.   ti: Integer;
  1208. begin
  1209.   ErrorCode := CB.Arg1; // error
  1210.   if ErrorCode < 0 then
  1211.     ErrorCode := -ErrorCode;
  1212. //  ti := CB.Arg2; // type
  1213.   if ErrorCode <> 0 then
  1214.     DllErrCode := ErrorCode;
  1215.   ti := CB.Arg2; // type
  1216.   if ReportSkipping(CB.msg, DllToErrCode(ErrorCode), TZMSkipTypes(pred(ti and MAX_BYTE))) then
  1217.     Result := CALLBACK_TRUE;
  1218. end;
  1219.  
  1220. procedure TZMDLLOpr.Done(Good: boolean = true);
  1221. begin
  1222.   inherited;
  1223.   if not Good then
  1224.     FPipes.Clear;
  1225. end;
  1226.  
  1227. (* ? TZMDLLOpr.ExtAdd
  1228. *)
  1229. procedure TZMDLLOpr.ExtAdd;
  1230. var
  1231.   CmdRecP: pDLLCommands;
  1232.   curz: TZMZipFile;
  1233.   MultiDisk: Boolean;
  1234.   ret: Integer;
  1235.   TmpZipName: String;
  1236. begin
  1237. //  { Make sure we can't get back in here while work is going on }
  1238.   SuccessCnt := 0;
  1239.   ClearErr;
  1240.   CmdRecP := nil;
  1241.   MultiDisk := zwoDiskSpan in WriteOptions;
  1242.   // We can not do an Unattended Add if we don't have a password.
  1243.   if Unattended and (AddEncrypt in AddOptions) and (Password = '') then
  1244.     raise EZipMaster.CreateResDisp(AD_UnattPassword, true);
  1245.   try
  1246.     GrabPipes;
  1247.     if ZipFileName = '' then // make sure we have a zip filename
  1248.       raise EZipMaster.CreateResDisp(GE_NoZipSpecified, true);
  1249.     if (FSpecArgs.Count = 0) then
  1250.     begin
  1251.       if not((AddFreshen in AddOptions) or (AddUpdate in AddOptions)) then
  1252.         raise EZipMaster.CreateResDisp(AD_NothingToZip, true);
  1253.       AddOptions := (AddOptions - [AddUpdate]) + [AddFreshen];
  1254.       FSpecArgs.Add(WILD_ALL); // do freshen all
  1255.     end;
  1256.  
  1257.     curz := CentralDir.Current;
  1258.     if curz.FileName = '' then
  1259.       curz.FileName := ZipFileName;
  1260.     curz.WorkDrive.HasMedia(False);
  1261.     // drive must exist and be changeable
  1262.     if Unattended and (not curz.WorkDrive.DriveIsFixed) and MultiDisk then
  1263.       raise EZipMaster.CreateResDisp(DS_NoUnattSpan, true);
  1264.  
  1265.     if (curz.Count = 0) and ((AddFreshen in AddOptions)) then
  1266.       raise EZipMaster.CreateResDisp(AD_NothingToZip, true);
  1267.  
  1268.     // make certain destination can exist
  1269.     { We must allow a zipfile to be specified that doesn't already exist,
  1270.       so don't check here for existance. }
  1271.     if (curz.WorkDrive.DriveIsFixed or not MultiDisk) then
  1272.     begin
  1273.       if zwoForceDest in WriteOptions then
  1274.         ForceDirectory(ExtractFilePath(ZipFileName));
  1275.       if not DirExists(ExtractFilePath(ZipFileName)) then
  1276.         raise EZipMaster.CreateResStr(AD_NoDestDir, ExtractFilePath(ZipFileName)
  1277.           );
  1278.     end;
  1279.  
  1280.     if not IsDestWritable(ZipFileName, MultiDisk) then
  1281.       raise EZipMaster.CreateResStr(DS_NotChangeable, ZipFileName);
  1282.  
  1283.     if _DLL_Load(self) <= 0 then
  1284.       exit; // could not load valid dll
  1285.     TmpZipName := ZipFileName; // default
  1286.     // If we are using disk spanning, first create a temporary file
  1287.     if (MultiDisk) then
  1288.     begin
  1289.       ret := RejoinMVArchive(TmpZipName);
  1290.       if ret <> 0 then
  1291.       begin
  1292.         _DLL_Unload(self);
  1293.         raise EZipMaster.CreateResDisp(ErrCode, true);
  1294.       end;
  1295.     end;
  1296.     if not MultiDisk and AnsiSameText(EXT_EXE, ExtractFileExt(ZipFileName))
  1297.       and not FileExists(ZipFileName) then
  1298.     begin
  1299.       { This is the first "add" operation following creation of a new
  1300.         .EXE archive.  We need to add the SFX code now, before we add
  1301.         the files. }
  1302.       ret := NewSFXFile(ZipFileName);
  1303.       if ret <> 0 then
  1304.         raise EZipMaster.CreateResInt(AD_AutoSFXWrong, AbsErr(ret));
  1305.     end;
  1306.   except
  1307.     on ews: EZipMaster do
  1308.     begin
  1309.       ShowExceptionError(ews);
  1310.       exit;
  1311.     end;
  1312.     else
  1313.       exit;
  1314.   end;
  1315.   Cancel := 0;
  1316.  
  1317.   try
  1318.     try
  1319.       CmdRecP := SetupZipCmd(TmpZipName);
  1320.       fEventErr := ''; // added
  1321.       { pass in a ptr to parms }
  1322.       SuccessCnt := _DLL_Exec(self, CmdRecP, fDLLOperKey);
  1323.       fEventErr := ''; // added
  1324.       if MultiDisk then
  1325.       begin
  1326.         if (SuccessCnt < 0) or RecreateMVArchive(TmpZipName,
  1327.              (CentralDir.Count > 0) and ((AddFreshen in AddOptions)
  1328.               or (AddUpdate in AddOptions))) then
  1329.           SysUtils.DeleteFile(TmpZipName);
  1330.       end;
  1331.     except
  1332.       on ews: EZipMaster do
  1333.       begin
  1334.         if fEventErr <> '' then
  1335.           ews.Message := ews.Message + fEventErr;
  1336.         ShowExceptionError(ews);
  1337.       end
  1338.       else
  1339.         ShowZipMessage(GE_FatalZip, '');
  1340.     end;
  1341.   finally
  1342.     FSpecArgs.Clear;
  1343.     FSpecArgsExcl.Clear;
  1344.     FPipes.Clear;
  1345.     DestroyDLLCmd(CmdRecP);
  1346.   end; { end try finally }
  1347.  
  1348.   _DLL_Unload(self);
  1349.   Cancel := 0;
  1350.   // Update the Zip Directory by calling List method
  1351.   // for spanned exe avoid swapping to last disk
  1352.   if (SuccessCnt > 0) and not IsDetachedSFX(ZipFileName) then
  1353.     List
  1354.   else
  1355.     CentralDir.Current := nil;
  1356. end;
  1357.  
  1358. (* ? TZMDLLOpr.ExtExtract
  1359.   *)
  1360. procedure TZMDLLOpr.ExtExtract;
  1361. var
  1362.   CmdRecP: pDLLCommands;
  1363.   DLLVers: Integer;
  1364.   good: boolean;
  1365.   OldPRC: Integer;
  1366.   TmpBaseDir: String;
  1367.   TmpS: String;
  1368.   TmpZipName: String;
  1369. begin
  1370.   SuccessCnt := 0;
  1371.   ClearErr;
  1372.   OldPRC := PasswordReqCount;
  1373.   DLLVers := 0;
  1374.   TmpZipName := '';
  1375.   CmdRecP := nil;
  1376.   good := True;
  1377.   Cancel := 0;
  1378.   try
  1379.     if (ZipFileName = '') then
  1380.       raise EZipMaster.CreateResDisp(GE_NoZipSpecified, true);
  1381.     if CentralDir.Count = 0 then
  1382.       List; // try again
  1383.     if CentralDir.Count = 0 then
  1384.     begin
  1385.       good := False; // stop from doing anything
  1386.       if ErrCode = 0 then // only show once
  1387.         raise EZipMaster.CreateResDisp(DS_FileOpen, true);
  1388.     end;
  1389.     Cancel := 0; // might have been set in List
  1390.     if good then
  1391.     begin
  1392.       TmpBaseDir := '';
  1393.       // expand and check ExtrBaseDir
  1394.       if (ExtrBaseDir <> '') and not(ExtrTest in ExtrOptions) then
  1395.       begin
  1396.         TmpBaseDir := ExpandUNCFileName(DelimitPath(ExtrBaseDir, true));
  1397.         if ExtrForceDirs in ExtrOptions then
  1398.           ForceDirectory(TmpBaseDir);
  1399.         if not DirExists(TmpBaseDir) then
  1400.           raise EZipMaster.CreateResStr(EX_NoExtrDir, TmpBaseDir);
  1401.       end;
  1402.  
  1403.       TmpZipName := ZipFileName;
  1404.  
  1405.       // We do a check if we need UnSpanning first, this depends on
  1406.       // The number of the disk the EOC record was found on. ( provided by List() )
  1407.       // If we have a spanned set consisting of only one disk we don't use ReadSpan().
  1408.       if CentralDir.TotalDisks > 1 then
  1409.       begin
  1410.         if TempDir = '' then
  1411.         begin
  1412.           SetLength(TmpS, MAX_PATH + 2);
  1413.           GetTempPath(MAX_PATH, PChar(TmpS));
  1414.           TmpZipName := PChar(TmpS); // convert from NULL terminated
  1415.           TmpS := '';
  1416.         end;
  1417.         TmpZipName := DelimitPath(TempDir, true);
  1418.         good := ReadSpan(ZipFileName, TmpZipName, true) = 0;
  1419.         // if we returned without an error, TmpZipName contains a real name.
  1420.       end;
  1421.     end; // if fUnzBusy then
  1422.  
  1423.     if good then
  1424.       DLLVers := _DLL_Load(self);
  1425.     if DLLVers > 0 then
  1426.       try
  1427.         GrabPipes;
  1428.         CmdRecP := SetupUnzCmd(TmpZipName);
  1429.         fEventErr := ''; // added
  1430.         // We have to be carefull doing an unattended Extract when a password is needed
  1431.         // for some file in the archive.
  1432.         if Unattended and (Password = '') and not assigned
  1433.           (Master.OnPasswordError) then
  1434.         begin
  1435.           PasswordReqCount := 0;
  1436.           ReportMsg(EX_UnAttPassword, []);
  1437.         end;
  1438.         SuccessCnt := _DLL_Exec(self, CmdRecP, fDLLOperKey);
  1439.       finally
  1440.         _DLL_Unload(self);
  1441.         FSpecArgs.Clear;
  1442.         FPipes.Clear;
  1443.         { If UnSpanned we still have this temporary file hanging around. }
  1444.         if CentralDir.TotalDisks > 1 then
  1445.           SysUtils.DeleteFile(TmpZipName);
  1446.         DestroyDLLCmd(CmdRecP);
  1447.  
  1448.         if Unattended and (Password = '') and not assigned
  1449.           (Master.OnPasswordError) then
  1450.           PasswordReqCount := OldPRC;
  1451.       end;
  1452.   except
  1453.     on ews: EZipMaster do
  1454.     begin
  1455.       if fEventErr <> '' then
  1456.         ews.Message := ews.Message + fEventErr;
  1457.       ShowExceptionError(ews);
  1458.       SuccessCnt := 0;
  1459.     end;
  1460.   end;
  1461.   { no need to call the List method; contents unchanged }
  1462. end;
  1463.  
  1464. procedure TZMDLLOpr.Extract;
  1465. begin
  1466.   fAutoStream := nil;
  1467.   ExtExtract;
  1468. end;
  1469.  
  1470. (* ? TZMDLLOpr.ExtractFileToStream
  1471.   1.73 15 July 2003 RA add check on FileName in FSpecArgs + return on busy
  1472.   *)
  1473. procedure TZMDLLOpr.ExtractFileToStream(const FileName: String);
  1474. var
  1475.   fn: String;
  1476. begin
  1477.   fn := Trim(FileName);
  1478.   if (Length(FileName) = 0) and (FSpecArgs.Count > 0) then
  1479.     fn := Trim(FSpecArgs[0]);
  1480.   if (fn = '') or IsWild(fn) then
  1481.   begin
  1482.     if fn <> '' then
  1483.       ShowZipMessage(AD_InvalidName, '')
  1484.     else
  1485.       ShowZipMessage(AD_NothingToZip, '');
  1486.     exit;
  1487.   end;
  1488.   FSpecArgs.Clear();
  1489.   FSpecArgs.Add('0:' + fn);
  1490.   SuccessCnt := 0;
  1491.   fAutoStream := ZipStream;
  1492.   fAutoDate := 0;
  1493.   fAutoAttr := 0;
  1494.   ZipStream.Clear();
  1495.   ExtExtract;
  1496.   fAutoStream := nil;
  1497. end;
  1498.  
  1499. (* ? TZMDLLOpr.ExtractStreamToStream
  1500.   1.73 14 July 2003 RA initial SuccessCnt
  1501.   *)
  1502. procedure TZMDLLOpr.ExtractStreamToStream(InStream: TMemoryStream;
  1503.   OutSize: Longword);
  1504. var
  1505.   crc: Cardinal;
  1506.   Header: TZM_StreamHeader;
  1507.   Method: TZMDeflates;
  1508.   realsize: Int64;
  1509. begin
  1510.   SuccessCnt := 0;
  1511.   ZipStream.Clear();
  1512.   if not assigned(InStream) then
  1513.   begin
  1514.     ShowZipMessage(AZ_NothingToDo, '');
  1515.     exit;
  1516.   end;
  1517.   if InStream = ZipStream then
  1518.   begin
  1519.     ShowZipMessage(AD_InIsOutStream, '');
  1520.     exit;
  1521.   end;
  1522.   realsize := InStream.Size - SizeOf(TZM_StreamHeader);
  1523.   if realsize > 0 then
  1524.   begin
  1525.     InStream.ReadBuffer(Header, SizeOf(TZM_StreamHeader));
  1526.     case Header.Method of
  1527.       METHOD_DEFLATED or TZMDeflateEncrypt: Method := zmDeflateEncrypt;
  1528.       METHOD_DEFLATED: Method := zmDeflate;
  1529.       METHOD_STORED: Method := zmStore;
  1530.     else
  1531.       begin
  1532.         ShowZipMessage(DS_Unsupported, '');
  1533.         ZipStream.size := 0;
  1534.         Exit;
  1535.       end;
  1536.     end;
  1537.     crc := Header.CRC;
  1538.     Undeflate(ZipStream, InStream, realsize, Method, crc);
  1539.     if SuccessCnt = 1 then
  1540.     begin
  1541. //      if crc <> crc0 then
  1542.       if crc <> Header.CRC then
  1543.       begin
  1544.         ShowZipMessage(DS_BadCRC, '');
  1545.         ZipStream.size := 0;
  1546.       end;
  1547.     end
  1548.     else
  1549.       ZipStream.size := 0;
  1550.   end;
  1551. end;
  1552.  
  1553. (* ? TZMWorker.GetAddPassword
  1554.   1.76 25 May 2004 changed
  1555.   1.76 10 May 2004 change loading strings
  1556.   *)
  1557. function TZMDLLOpr.GetAddPassword(var Response: TmsgDlgBtn): String;
  1558. var
  1559.   p1: String;
  1560.   p2: String;
  1561. begin
  1562.   p2 := '';
  1563.   if Unattended then
  1564.     ShowZipMessage(PW_UnatAddPWMiss, '')
  1565.   else
  1566.   begin
  1567.     Response := GetPassword(ZipLoadStr(PW_Caption), ZipLoadStr
  1568.         (PW_MessageEnter), DHC_AddPwrd1, mbOkCancel, p1);
  1569.     if (Response = mbOK) and (p1 <> '') then
  1570.     begin
  1571.       Response := GetPassword(ZipLoadStr(PW_Caption), ZipLoadStr
  1572.           (PW_MessageConfirm), DHC_AddPWrd2, mbOkCancel, p2);
  1573.       if (Response = mbOK) and (p2 <> '') then
  1574.         if {Ansi}CompareStr(p1, p2) <> 0 then
  1575.         begin
  1576.           ShowZipMessage(GE_WrongPassword, '');
  1577.           p2 := '';
  1578.         end;
  1579.     end;
  1580.   end;
  1581.   Result := p2;
  1582. end;
  1583.  
  1584. function TZMDLLOpr.GetDLL_Build: Integer;
  1585. begin
  1586.   Result := _DLL_Build;
  1587. end;
  1588.  
  1589. function TZMDLLOpr.GetDLL_Load: Boolean;
  1590. begin
  1591.   Result := _DLL_Loaded(self);
  1592. {$IFDEF ZDEBUG}
  1593.   Diag('DLL_Load = ' + IntToStr(Ord(Result)));
  1594. {$ENDIF}
  1595. end;
  1596.  
  1597. function TZMDLLOpr.GetDLL_Path: string;
  1598. begin
  1599.   Result := _DLL_Path;
  1600. end;
  1601.  
  1602. function TZMDLLOpr.DLL_Version(Load: Boolean): string;
  1603. begin
  1604.   if Load then
  1605.     _DLL_Load(self);
  1606.   Result := VersStr(_DLL_Build, False);
  1607.   if Load then
  1608.     _DLL_Unload(self);
  1609. end;
  1610.  
  1611. (* ? TZMWorker.GetExtrPassword
  1612.   1.76 25 May 2004 changed
  1613.   1.76 10 May 2004 change loading strings
  1614.   Same as GetAddPassword, but does NOT verify
  1615.   *)
  1616. function TZMDLLOpr.GetExtrPassword(var Response: TmsgDlgBtn): String;
  1617. begin
  1618.   Result := '';
  1619.   if Unattended then
  1620.     ShowZipMessage(PW_UnatExtPWMiss, '')
  1621.   else
  1622.     Response := GetPassword(ZipLoadStr(PW_Caption), ZipLoadStr
  1623.         (PW_MessageEnter), DHC_ExtrPwrd, [mbOK, mbCancel, mbAll], Result);
  1624. end;
  1625.  
  1626. (* ? TZMWorker.GetPassword
  1627.   1.76 25 May 2004 no external GlobalResult
  1628.   *)
  1629. function TZMDLLOpr.GetPassword(const DialogCaption, MsgTxt: String;
  1630.   ctx: Integer; pwb: TmsgDlgButtons; var ResultStr: String): TmsgDlgBtn;
  1631. var
  1632.   GModalResult: TModalResult;
  1633.   msg: String;
  1634. begin
  1635.   msg := MsgTxt;
  1636.   ResultStr := '';
  1637.   GModalResult := ZipMessageDialog(DialogCaption, msg, zmtPassword +
  1638.       (ctx and MAX_WORD), pwb);
  1639.   case GModalResult of
  1640.     mrOk:
  1641.       begin
  1642.         ResultStr := msg;
  1643.         Result := mbOK;
  1644.       end;
  1645.     mrCancel:
  1646.       Result := mbCancel;
  1647.     mrAll:
  1648.       Result := mbNoToAll;
  1649.   else
  1650.     Result := mbAbort;
  1651.   end;
  1652. end;
  1653.  
  1654. function TZMDLLOpr.GetPassword(const DialogCaption, MsgTxt: String;
  1655.   pwb: TmsgDlgButtons; var ResultStr: String): TmsgDlgBtn;
  1656. begin
  1657.   Result := GetPassword(DialogCaption, MsgTxt, DHC_Password, pwb, ResultStr);
  1658. end;
  1659.  
  1660. procedure TZMDLLOpr.GrabPipes;
  1661. var
  1662.   i: Integer;
  1663.   fn: String;
  1664.   MasterPipes: TZMPipeListImp;
  1665. begin
  1666.   MasterPipes := Master.Pipes as TZMPipeListImp;
  1667.   MasterPipes.AssignTo(Pipes);
  1668.   //  Add names to start of FSpecArgs
  1669.   if Pipes.Count > 0 then
  1670.   begin
  1671.     for I := 0 to Pipes.Count - 1 do
  1672.     begin
  1673.       fn := Pipes[I].FileName;
  1674.       if (fn <> '') and IsInvalidIntName(fn) then
  1675.         raise EZipMaster.CreateResDisp(AD_BadFileName, true);
  1676.       while (fn <> '') and (fn[1] = '\') do
  1677.         fn := Copy(fn, 2, MAX_PATH);
  1678.       if fn = '' then
  1679.         fn := '#stream' + IntToStr(I) + '#';
  1680.       fn := IntToStr(I) + ':' + fn;
  1681.       FSpecArgs.Insert(I, fn);
  1682.     end;
  1683.   end;
  1684. end;
  1685.  
  1686. procedure TZMDLLOpr.Kill;
  1687. begin
  1688.   fIsDestructing := true; // stop callbacks
  1689.   AbortDLL;
  1690.   inherited;
  1691. end;
  1692.  
  1693. procedure TZMDLLOpr.SetCB(const Value: TDZCallback);
  1694. begin
  1695.   if fCB <> Value then
  1696.   begin
  1697.     fCB := Value;
  1698.   end;
  1699. end;
  1700.  
  1701. procedure TZMDLLOpr.SetDLL_Load(const Value: Boolean);
  1702. begin
  1703. {$IFDEF ZDEBUG}
  1704.   Diag('set DLL_Load to ' + IntToStr(Ord(Value)));
  1705. {$ENDIF}
  1706.   if Value <> fDidLoad then
  1707.   begin
  1708.     if Value then
  1709.     begin
  1710.       fDidLoad := _DLL_Load(self) > 0;
  1711.     end
  1712.     else
  1713.     begin
  1714.       _DLL_Unload(self);
  1715.       fDidLoad := False;
  1716.     end;
  1717. {$IFDEF ZDEBUG}
  1718.     Diag('changed DLL_Load to ' + IntToStr(Ord(Value)));
  1719. {$ENDIF}
  1720.   end;
  1721. end;
  1722.  
  1723. procedure TZMDLLOpr.SetExtAddStoreSuffixes(const Value: String);
  1724. var
  1725.   c: Char;
  1726.   i: Integer;
  1727.   tempStr: String;
  1728. begin
  1729.   if Value <> '' then
  1730.   begin
  1731.     c := ':';
  1732.     i := 1;
  1733.     while i <= Length(Value) do
  1734.     begin
  1735.       c := Value[i];
  1736.       if c <> '.' then
  1737.         tempStr := tempStr + '.';
  1738.       while (c <> ':') and (i <= Length(Value)) do
  1739.       begin
  1740.         c := Value[i];
  1741.         if (c = ';') or (c = ':') or (c = ',') then
  1742.           c := ':';
  1743.         tempStr := tempStr + c;
  1744.         Inc(i);
  1745.       end;
  1746.     end;
  1747.     if c <> ':' then
  1748.       tempStr := tempStr + ':';
  1749.     fAddStoreSuffixes := fAddStoreSuffixes + [assEXT];
  1750.     fExtAddStoreSuffixes := Lowercase(tempStr);
  1751.   end
  1752.   else
  1753.   begin
  1754.     fAddStoreSuffixes := fAddStoreSuffixes - [assEXT];
  1755.     fExtAddStoreSuffixes := '';
  1756.   end;
  1757. end;
  1758.  
  1759. procedure TZMDLLOpr.SetPipes(const Value: TZMPipeListImp);
  1760. begin
  1761. //
  1762. end;
  1763.  
  1764. function TZMDLLOpr.SetupUnzCmd(const Value: String): pDLLCommands;
  1765. var
  1766.   Opts: Cardinal;
  1767. begin
  1768.   Result := AllocDLLCommand(Value);
  1769.   if Result <> nil then
  1770.   begin
  1771.     Opts := Result^.fOptions;
  1772.     if ExtrNTFS in ExtrOptions then
  1773.       Opts := Opts or DLL_OPT_NTFSStamps;
  1774.     if ExtrDirNames in ExtrOptions then
  1775.       Opts := Opts or DLL_OPT_Directories;
  1776.     if ExtrOverWrite in ExtrOptions then
  1777.       Opts := Opts or DLL_OPT_Overwrite;
  1778.     if ExtrUpdate in ExtrOptions then
  1779.       Opts := Opts or DLL_OPT_Update
  1780.     else if ExtrFreshen in ExtrOptions then
  1781.       Opts := Opts or DLL_OPT_Freshen;
  1782.     { Update has precedence over freshen }
  1783.  
  1784.     if ExtrTest in ExtrOptions then
  1785.       Opts := Opts or DLL_OPT_OpIsTest
  1786.     else
  1787.       Opts := Opts or DLL_OPT_OpIsUnz;
  1788.  
  1789.     Result^.fPwdReqCount := PasswordReqCount;
  1790.     Result^.fOptions := Opts;
  1791.     Result^.fCheck := DLLCOMMANDCHECK;
  1792.   end;
  1793. end;
  1794.  
  1795. function TZMDLLOpr.SetupZipCmd(const Value: String): pDLLCommands;
  1796. var
  1797.   Opts: Cardinal;
  1798. begin
  1799.   Result := AllocDLLCommand(Value);
  1800.   if Result <> nil then
  1801.   begin
  1802.     Opts := Result^.fOptions;
  1803.     Result^.fEncodedAs := 0; // how to interpret existing names
  1804.     if Encoding = zeoOEM then
  1805.       Result^.fEncodedAs := Ord(zeoOEM)
  1806.     else if Encoding = zeoUTF8 then
  1807.       Result^.fEncodedAs := Ord(zeoUTF8);
  1808.     Result^.fEncodeAs := Ord(EncodeAs); // how to encode new names
  1809.  
  1810.     if AddArchiveOnly in AddOptions then
  1811.       Opts := Opts or DLL_OPT_ArchiveFilesOnly;
  1812.     if AddResetArchive in AddOptions then
  1813.       Opts := Opts or DLL_OPT_ResetArchiveBit;
  1814.  
  1815.     if HowToDelete = htdAllowUndo then
  1816.       Opts := Opts or DLL_OPT_HowToMove;
  1817.     if AddVersion in AddOptions then
  1818.       Opts := Opts or DLL_OPT_Versioning;
  1819.     if AddVolume in AddOptions then
  1820.       Opts := Opts or DLL_OPT_Volume;
  1821.  
  1822.     { if True, exclude files earlier than specified date }
  1823.     { Date to include files after; only used if fDate=TRUE }
  1824.     if AddFromDate in AddOptions then
  1825.       Result^.fDate := DateTimeToFileDate(FromDate);
  1826.     // Compression level (0 - 9, 0=none and 9=best)
  1827.     Result^.fLevel := AddCompLevel;
  1828.     if not(AddSafe in AddOptions) then
  1829.       Opts := Opts or DLL_OPT_Grow;
  1830.     { if True, Allow appending to a zip file (-g) }
  1831.     if AddNTFS in AddOptions then
  1832.       Opts := Opts or DLL_OPT_NTFSStamps;
  1833.  
  1834.     // distinguish bet. Add and Delete
  1835.     Opts := Opts or DLL_OPT_OpIsZip;
  1836.  
  1837.     // make zipfile's timestamp same as newest file
  1838.     if zwoZipTime in WriteOptions then
  1839.       Opts := Opts or DLL_OPT_LatestTime;
  1840.  
  1841.     if AddMove in AddOptions then
  1842.       Opts := Opts or DLL_OPT_Move; // dangerous, beware!
  1843.  
  1844.     if AddUpdate in AddOptions then
  1845.       Opts := Opts or DLL_OPT_Update
  1846.     else if AddFreshen in AddOptions then
  1847.       Opts := Opts or DLL_OPT_Freshen;
  1848.     // { Update has precedence over freshen }
  1849.  
  1850.     { DLL will prompt for password }
  1851.     if AddEncrypt in AddOptions then
  1852.       Opts := Opts or DLL_OPT_Encrypt;
  1853.     { NOTE: if user wants recursion, then he probably also wants
  1854.       AddDirNames, but we won't demand it. }
  1855.     if AddRecurseDirs in AddOptions then
  1856.       Opts := Opts or DLL_OPT_Recurse;
  1857.     if AddHiddenFiles in AddOptions then
  1858.       Opts := Opts or DLL_OPT_System;
  1859. //    if not(AddSeparateDirs in AddOptions) then
  1860. //      Opts := Opts or DLL_OPT_NoDirEntries;
  1861. //    if AddNoSeparateDirs in AddOptions then
  1862.     if not (AddEmptyDirs in AddOptions) then
  1863.       Opts := Opts or DLL_OPT_NoDirEntries;
  1864.     { don't store dirnames with filenames }
  1865.     if not(AddDirNames in AddOptions) then
  1866.       Opts := Opts or DLL_OPT_JunkDir;
  1867.  
  1868.     Result^.fOptions := Opts;
  1869.     Result^.fCheck := DLLCOMMANDCHECK;
  1870.   end;
  1871. end;
  1872.  
  1873. procedure TZMDLLOpr.StartUp;
  1874. begin
  1875.   inherited StartUp;
  1876.   fAddCompLevel := Master.AddCompLevel;
  1877.   fFromDate := Master.AddFrom;
  1878.   fAddStoreSuffixes := Master.AddStoreSuffixes;
  1879.   ExtAddStoreSuffixes := Master.ExtAddStoreSuffixes;
  1880.   fExtrBaseDir := Master.ExtrBaseDir;
  1881.   fExtrOptions := Master.ExtrOptions;
  1882.   fPassword := Master.Password;
  1883.   fPasswordReqCount := Master.PasswordReqCount;
  1884.   fRootDir := Master.RootDir;
  1885. end;
  1886.  
  1887. procedure TZMDLLOpr.Undeflate(OutStream, InStream: TStream; Length: Int64; var
  1888.     Method: tzMDeflates; var crc: Cardinal);
  1889. var
  1890.   Args: TZSSArgs;
  1891.   CmdRecP: pDLLCommands;
  1892.   i: Integer;
  1893.   ncrypt: boolean;
  1894. begin
  1895.   SuccessCnt := 0;
  1896.   ClearErr;
  1897.   if not assigned(InStream) then
  1898.   begin
  1899.     ShowZipMessage(DS_NoInStream, '');
  1900.     exit;
  1901.   end;
  1902.   if not assigned(OutStream) then
  1903.   begin
  1904.     ShowZipMessage(DS_NoOutStream, '');
  1905.     exit;
  1906.   end;
  1907.   if InStream = ZipStream then
  1908.   begin
  1909.     ShowZipMessage(AD_InIsOutStream, '');
  1910.     exit;
  1911.   end;
  1912.   ncrypt := (Method = zmStoreEncrypt) or (Method = zmDeflateEncrypt);
  1913.   // We can not do an Unattended Add if we don't have a password.
  1914.   if Unattended and ncrypt and (Password = '') then
  1915.   begin
  1916.     ShowZipMessage(EX_UnAttPassword, '');
  1917.     exit;
  1918.   end;
  1919.   if Length < 0 then
  1920.     Length := InStream.size;
  1921.   CmdRecP := nil;
  1922.   if (Method = zmDeflate) or (Method = zmDeflateEncrypt) then
  1923.     Args.Method := METHOD_DEFLATED
  1924.   else
  1925.     Args.Method := METHOD_STORED;
  1926.   if ncrypt then
  1927.     Args.Method := Args.Method or TZMDeflateEncrypt;//1024;
  1928.   Args.fSSInput := InStream;
  1929.   Args.fSSOutput := OutStream;
  1930.   Args.size := Length;
  1931.   Args.crc := crc;
  1932.   if _DLL_Load(self) <= 0 then
  1933.   begin
  1934.     ShowZipMessage(LD_NoDLL, DelZipDLL_Name);
  1935.     exit;
  1936.   end;
  1937.   try
  1938. //    fUnzBusy := true;
  1939.     Cancel := 0;
  1940.     CmdRecP := SetupUnzCmd('<UNDEFLATE>'); // do not localize
  1941.     CmdRecP^.fSS := @Args;
  1942.     fEventErr := ''; // added
  1943.     { pass in a ptr to parms }
  1944.     i := _DLL_Exec(self, CmdRecP, fDLLOperKey);
  1945.   finally
  1946.     _DLL_Unload(self);
  1947.     DestroyDLLCmd(CmdRecP);
  1948.   end;
  1949.   if i = 1 then
  1950.   begin // success
  1951.     SuccessCnt := 1;
  1952.     if Args.Method = METHOD_DEFLATED then
  1953.       Method := zmDeflate
  1954.     else
  1955.       Method := zmStore;
  1956.     crc := Args.crc;
  1957.   end;
  1958. end;
  1959.  
  1960. constructor TDZCallback.Create(theWorker: TZMWorker);
  1961. begin
  1962.   fWorker := theWorker;
  1963.   PCB := nil;
  1964.   fHeldData := nil;
  1965.   fHoldSize := 0;
  1966. end;
  1967.  
  1968. destructor TDZCallback.Destroy; // override;
  1969. begin
  1970.   if fHeldData <> nil then
  1971.     FreeMem(fHeldData);
  1972.   fHeldData := nil;
  1973. end;
  1974.  
  1975. function TDZCallback.Assign(ZCallBackRec: PZCallBackStruct): Integer;
  1976. begin
  1977.   PCB := ZCallBackRec;
  1978.   if PCB = nil then
  1979.     Result := 1
  1980.   else
  1981.     Result := 0;
  1982. end;
  1983.  
  1984. procedure TDZCallback.Clear;
  1985. begin
  1986.   if fHeldData <> nil then
  1987.     FreeMem(fHeldData);
  1988.   fHeldData := nil;
  1989.   fHoldSize := 0;
  1990.   PCB := nil; // ??
  1991. end;
  1992.  
  1993. function TDZCallback.CopyData(dst: PByte; MaxSize: Integer): Boolean;
  1994. var
  1995.   sz: Integer;
  1996. begin
  1997.   Result := False;
  1998.   sz := Arg1;
  1999.   if sz > MaxSize then
  2000.     sz := MaxSize;
  2001.   if sz > 0 then
  2002.   begin
  2003.     move(PCB^.Msg2P^, dst^, sz);
  2004.     Result := true;
  2005.   end;
  2006. end;
  2007.  
  2008. function TDZCallback.GetActionCode: Integer;
  2009. begin
  2010.   Result := PCB^.ActionCode;
  2011. end;
  2012.  
  2013. function TDZCallback.GetArg1: Cardinal;
  2014. begin
  2015.   Result := PCB^.Arg1;
  2016. end;
  2017.  
  2018. function TDZCallback.GetArg2: Cardinal;
  2019. begin
  2020.   Result := PCB^.Arg2;
  2021. end;
  2022.  
  2023. function TDZCallback.GetArg3: Integer;
  2024. begin
  2025.   Result := PCB^.Arg3;
  2026. end;
  2027.  
  2028. function TDZCallback.GetFile_Size: Int64;
  2029. begin
  2030.   Result := PCB^.File_Size;
  2031. end;
  2032.  
  2033. function TDZCallback.GetIsZip: Boolean;
  2034. begin
  2035.   Result := PCB^.IsOperationZip;
  2036. end;
  2037.  
  2038. function TDZCallback.GetMsg: TZMString;
  2039. begin
  2040.   Result := GetMsgStr(PCB^.MsgP);
  2041. end;
  2042.  
  2043. function TDZCallback.GetMsg2: TZMString;
  2044. begin
  2045.   Result := GetMsgStr(PCB^.Msg2P);
  2046. end;
  2047.  
  2048. function TDZCallback.GetMsgStr(const msg: PByte): TZMString;
  2049. {$IFNDEF UNICODE}
  2050. var
  2051.   utemp: UTF8String;
  2052. {$ENDIF}
  2053. begin
  2054.   Result := '';
  2055.   if msg <> nil then
  2056.   begin
  2057. {$IFDEF UNICODE}
  2058.     if PCB^.HaveWide <> 0 then
  2059.       Result := PWideChar(msg)
  2060.     else
  2061.       Result := PUTF8ToWideStr(PAnsiChar(msg), -1);
  2062. {$ELSE}
  2063.     if fWorker.UseUtf8 then
  2064.     begin
  2065.       if PCB^.HaveWide <> 0 then
  2066.         Result := PWideToUTF8(PWideChar(msg), -1)
  2067.       else
  2068.       begin
  2069.         utemp := PAnsiChar(msg);
  2070.         Result := StrToUTF8(utemp);
  2071.       end;
  2072.     end
  2073.     else
  2074.     begin
  2075.       if PCB^.HaveWide <> 0 then
  2076.         Result := PWideChar(msg) // will convert wide -> ansi
  2077.       else
  2078.         Result := PAnsiChar(msg);
  2079.     end;
  2080. {$ENDIF}
  2081.   end;
  2082. end;
  2083.  
  2084. function TDZCallback.GetOwner: TZMDLLOpr;
  2085. begin
  2086.   Result := TObject(PCB^.Caller) as TZMDLLOpr;
  2087. end;
  2088.  
  2089. function TDZCallback.GetWritten: Int64;
  2090. begin
  2091.   Result := PCB^.Written;
  2092. end;
  2093.  
  2094. function TDZCallback.HoldData(const src: PByte; size: Cardinal): PByte;
  2095. var
  2096.   len: Integer;
  2097.   p: PByte;
  2098. begin
  2099.   if src = nil then
  2100.   begin
  2101.     // free buffer
  2102.     FreeMem(fHeldData);
  2103.     fHeldData := nil;
  2104.     fHoldSize := 0;
  2105.     Result := fHeldData;
  2106.     exit;
  2107.   end;
  2108.   if fHeldData = nil then
  2109.     fHoldSize := 0;
  2110.   len := size + sizeof(Integer);
  2111.   if (fHeldData = nil) or (len >= fHoldSize) then
  2112.   begin
  2113.     if fHeldData <> nil then
  2114.       FreeMem(fHeldData);
  2115.     fHeldData := nil;
  2116.     len := (len or 511) + 1;  // increments of 512
  2117.     GetMem(fHeldData, len);
  2118.     fHoldSize := len;
  2119.   end;
  2120.   p := fHeldData;
  2121.   if size > 0 then
  2122.   begin
  2123.     move(src^, fHeldData^, size);
  2124.     Inc(p, size);
  2125.   end;
  2126.   PCardinal(p)^ := 0; // mark end
  2127.   Result := fHeldData;
  2128. end;
  2129.  
  2130. function TDZCallback.HoldString(const src: TZMString): PByte;
  2131. var
  2132.   len: Integer;
  2133. begin
  2134.   len := Length(src) * sizeof(Char);
  2135.   if len > 0 then
  2136.     Result := HoldData(PByte(PChar(src)), len)
  2137.   else
  2138.     Result := HoldData(PByte(@len), 0);  // avoid freeing hold area
  2139. end;
  2140.  
  2141. procedure TDZCallback.SetArg1(const Value: Cardinal);
  2142. begin
  2143.   PCB^.Arg1 := Value;
  2144. end;
  2145.  
  2146. procedure TDZCallback.SetArg2(const Value: Cardinal);
  2147. begin
  2148.   PCB^.Arg2 := Value;
  2149. end;
  2150.  
  2151. procedure TDZCallback.SetArg3(const Value: Integer);
  2152. begin
  2153.   PCB^.Arg3 := Value;
  2154. end;
  2155.  
  2156. procedure TDZCallback.SetComment(const AStr: AnsiString);
  2157. begin
  2158.   PCB^.HaveWide := 0;
  2159.   PCB^.MsgP := HoldData(PByte(PAnsiChar(AStr)), Length(AStr));
  2160.   PCB^.Arg1 := Cardinal(Length(AStr));
  2161. end;
  2162.  
  2163. procedure TDZCallback.SetData(src: PByte; size: Integer);
  2164. begin
  2165.   if size > 2048 then
  2166.     size := 2048;
  2167.   PCB^.MsgP := HoldData(src, size);
  2168.   PCB^.Arg1 := Cardinal(size);
  2169. end;
  2170.  
  2171. procedure TDZCallback.SetFile_Size(const Value: Int64);
  2172. begin
  2173.   PCB^.File_Size := Value;
  2174. end;
  2175.  
  2176. procedure TDZCallback.SetMsg(const Value: TZMString);
  2177. begin
  2178. {$IFDEF UNICODE}
  2179.   PCB^.HaveWide := 1; // Unicode
  2180. {$ELSE}
  2181.   if fWorker.UseUtf8 and (ValidUTF8(Value, -1) > 0) then
  2182.     PCB^.HaveWide := 2 // UTF8
  2183.   else
  2184.     PCB^.HaveWide := 0; // Ansi
  2185. {$ENDIF}
  2186.   PCB^.MsgP := HoldString(Value);
  2187. end;
  2188.  
  2189. end.
  2190.