ZipMstr.pas
Upload User: hzbigears
Upload Date: 2019-12-19
Package Size: 571k
Code Size: 215k
Development Platform:

Delphi

  1. unit ZipMstr;
  2. (* TZipMaster VCL by Chris Vleghert and Eric W. Engler
  3.    e-mail: englere@abraxis.com
  4.    www:    http://www.geocities.com/SiliconValley/Network/2114
  5.  v1.70 by Russell Peters August 2, 2002.
  6.             *)
  7. //{$DEFINE NO_SPAN}
  8. //{$DEFINE NO_SFX}
  9. {$INCLUDE ZipVers.inc}
  10. {$IFDEF VER140}
  11. {$WARN UNIT_PLATFORM OFF}
  12. {$WARN SYMBOL_PLATFORM OFF}
  13. {$ENDIF}
  14. interface
  15. uses
  16.     Forms, WinTypes, WinProcs, SysUtils, Classes, Messages, Dialogs, Controls,
  17.     ZipDLL, UnzDLL, ZCallBck, ZipMsg, ShellApi, Graphics, Buttons, StdCtrls,
  18.     FileCtrl;
  19. const
  20.     ZIPMASTERVERSION: string = '1.70';
  21.     ZIPMASTERBUILD: string = '1.7.0.5';
  22.     Min_ZipDll_Vers: integer = 170;
  23.     Min_UnzDll_Vers: integer = 170;
  24.     {$IFDEF VERD2D3}
  25. type
  26.     LargeInt = Comp;
  27. type
  28.     pLargeInt = ^Comp;
  29. type
  30.     LongWord = Cardinal;
  31. const
  32.     mrNoToAll = mrNo + 1;
  33.     {$ENDIF}
  34.     {$IFDEF VERD4+}
  35. type
  36.     LargeInt = Int64;
  37. type
  38.     pLargeInt = ^Int64;
  39.     {$ENDIF}
  40.     //------------------------------------------------------------------------
  41. type
  42.     ProgressType = (NewFile, ProgressUpdate, EndOfBatch, TotalFiles2Process,
  43.         TotalSize2Process);
  44.     AddOptsEnum = (AddDirNames, AddRecurseDirs, AddMove, AddFreshen, AddUpdate,
  45.         AddZipTime, AddForceDOS, AddHiddenFiles, AddArchiveOnly, AddResetArchive,
  46. AddEncrypt, AddSeparateDirs, AddVolume, AddFromDate, AddDiskSpan, AddDiskSpanErase);
  47. AddOpts = set of AddOptsEnum;
  48.     // When changing this enum also change the pointer array in the function AddSuffix,
  49.     // and the initialisation of ZipMaster. Also keep assGIF as first and assEXE as last value.
  50.     AddStoreSuffixEnum = (assGIF, assPNG, assZ, assZIP, assZOO, assARC,
  51.         assLZH, assARJ, assTAZ, assTGZ, assLHA, assRAR,
  52.         assACE, assCAB, assGZ, assGZIP, assJAR, assEXE);
  53.     AddStoreExts = set of AddStoreSuffixEnum;
  54. ExtrOptsEnum = (ExtrDirNames, ExtrOverWrite, ExtrFreshen, ExtrUpdate, ExtrTest);
  55.     ExtrOpts = set of ExtrOptsEnum;
  56.     SFXOptsEnum = (SFXAskCmdLine, SFXAskFiles, SFXAutoRun, SFXHideOverWriteBox, SFXCheckSize, SFXNoSuccessMsg);
  57.     SFXOpts = set of SFXOptsEnum;
  58.     OvrOpts = (OvrConfirm, OvrAlways, OvrNever);
  59.     CodePageOpts = (cpAuto, cpNone, cpOEM);
  60.     CodePageDirection = (cpdOEM2ISO, cpdISO2OEM);
  61.     DeleteOpts = (htdFinal, htdAllowUndo);
  62.     UnZipSkipTypes = (stOnFreshen, stNoOverwrite, stFileExists, stBadPassword, stNoEncryptionDLL,
  63.         stCompressionUnknown, stUnknownZipHost, stZipFileFormatWrong, stGeneralExtractError);
  64.     ZipDiskStatusEnum = (zdsEmpty, zdsHasFiles, zdsPreviousDisk, zdsSameFileName, zdsNotEnoughSpace);
  65.     TZipDiskStatus = set of ZipDiskStatusEnum;
  66.     TZipDiskAction = (zdaOk, zdaErase, zdaReject, zdaCancel);
  67. type
  68.     ZipDirEntry = packed record         // fixed part size = 42
  69.         MadeByVersion: Byte;
  70.         HostVersionNo: Byte;
  71.         Version: Word;
  72.         Flag: Word;
  73.         CompressionMethod: Word;
  74.         DateTime: Integer;              // Time: Word; Date: Word; }
  75.         CRC32: Integer;
  76.         CompressedSize: Integer;
  77.         UncompressedSize: Integer;
  78.         FileNameLength: Word;
  79.         ExtraFieldLength: Word;
  80.         FileCommentLen: Word;
  81.         StartOnDisk: Word;
  82.         IntFileAttrib: Word;
  83.         ExtFileAttrib: LongWord;
  84.         RelOffLocalHdr: LongWord;
  85.         FileName: string;               // variable size
  86.         FileComment: string;            // variable size
  87.         Encrypted: Boolean;
  88.         ExtraData: pChar;               // New v1.6, used in CopyZippedFiles()
  89.     end;
  90.     pZipDirEntry = ^ZipDirEntry;
  91. type
  92.     ZipEndOfCentral = packed record     //Fixed part size : 22 bytes
  93.         HeaderSig: LongWord;            //(4)  hex=06054B50
  94.         ThisDiskNo: Word;               //(2)This disk's number
  95.         CentralDiskNo: Word;            //(2)Disk number central dir start
  96.         CentralEntries: Word;           //(2)Number of central dir entries on this disk
  97.         TotalEntries: Word;             //(2)Number of entries in central dir
  98.         CentralSize: LongWord;          //(4)Size of central directory
  99.         CentralOffSet: LongWord;        //(4)offsett of central dir on 1st disk
  100.         ZipCommentLen: Word;            //(2)
  101.         // not used as part of this record structure:
  102.         // ZipComment
  103.     end;
  104. type
  105.     ZipRenameRec = record
  106.         Source: string;
  107.         Dest: string;
  108.         DateTime: Integer;
  109.     end;
  110.     pZipRenameRec = ^ZipRenameRec;
  111. type
  112.     EZipMaster = class(Exception)
  113.     public
  114.         FDisplayMsg: Boolean;           // We do not always want to see a message after an exception.
  115.         // We also save the Resource ID in case the resource is not linked in the application.
  116.         FResIdent: Integer;
  117.         constructor CreateResDisp(const Ident: Integer; const Display: Boolean);
  118.         constructor CreateResDisk(const Ident: Integer; const DiskNo: Integer);
  119.         constructor CreateResDrive(const Ident: Integer; const Drive: string);
  120.         constructor CreateResFile(const Ident: Integer; const File1, File2: string);
  121.     end;
  122.     TPasswordButton = (pwbOk, pwbCancel, pwbCancelAll, pwbAbort);
  123.     TPasswordButtons = set of TPasswordButton;
  124.     TProgressEvent = procedure(Sender: TObject; ProgrType: ProgressType; Filename: string; FileSize: Integer) of object;
  125.     TMessageEvent = procedure(Sender: TObject; ErrCode: Integer; Message: string) of object;
  126.     TSetNewNameEvent = procedure(Sender: TObject; var OldFileName: string; var IsChanged: Boolean) of object;
  127.     TNewNameEvent = procedure(Sender: TObject; SeqNo: Integer; ZipEntry: ZipDirEntry) of object;
  128.     TPasswordErrorEvent = procedure(Sender: TObject; IsZipAction: Boolean; var NewPassword: string; ForFile: string; var RepeatCount: LongWord; var Action: TPasswordButton) of object;
  129.     TCRC32ErrorEvent = procedure(Sender: TObject; ForFile: string; FoundCRC, ExpectedCRC: LongWord; var DoExtract: Boolean) of object;
  130.     TExtractOverwriteEvent = procedure(Sender: TObject; ForFile: string; IsOlder: Boolean; var DoOverwrite: Boolean; DirIndex: Integer) of object;
  131.     TExtractSkippedEvent = procedure(Sender: TObject; ForFile: string; SkipType: UnZipSkipTypes; ExtError: Integer) of object;
  132.     TCopyZipOverwriteEvent = procedure(Sender: TObject; ForFile: string; var DoOverwrite: Boolean) of object;
  133.     TGetNextDiskEvent = procedure(Sender: TObject; DiskSeqNo, DiskTotal: Integer; Drive: string; var AbortAction: Boolean) of object;
  134.     TStatusDiskEvent = procedure(Sender: TObject; PreviousDisk: Integer; PreviousFile: string; Status: TZipDiskStatus; var Action: TZipDiskAction) of object;
  135.     TFileCommentEvent = procedure(Sender: TObject; ForFile: string; var FileComment: string; var IsChanged: Boolean) of object;
  136.     TZipStream = class(TMemoryStream)
  137.     public
  138.         constructor Create;
  139.         destructor Destroy; override;
  140.         procedure SetPointer(Ptr: Pointer; Size: Integer); virtual;
  141.     end;
  142.     TZipMaster = class(TComponent)
  143.     private
  144.         // fields of published properties
  145.         FAddCompLevel: Integer;
  146.         fAddOptions: AddOpts;
  147.         FAddStoreSuffixes: AddStoreExts;
  148.         { Private versions of property variables }
  149.         fCancel: Boolean;
  150.         FDirOnlyCount: Integer;
  151.         fErrCode: Integer;
  152.         fFullErrCode: Integer;
  153.         fHandle: HWND;
  154.         FIsSpanned: Boolean;
  155.         fMessage: string;
  156.         fVerbose: Boolean;
  157.         fTrace: Boolean;
  158.         fZipContents: TList;
  159.         fExtrBaseDir: string;
  160.         fZipBusy: Boolean;
  161.         fUnzBusy: Boolean;
  162.         FExtrOptions: ExtrOpts;
  163.         FFSpecArgs: TStrings;
  164.         FZipFileName: string;
  165.         FSuccessCnt: Integer;
  166.         FPassword: ShortString;
  167.         FEncrypt: Boolean;
  168.         FSFXOffset: Integer;
  169.         FDLLDirectory: string;
  170.         FUnattended: Boolean;
  171.         AutoExeViaAdd: Boolean;
  172.         FVolumeName: string;
  173.         FSizeOfDisk: LargeInt;          { Int64 or Comp }
  174.         FDiskFree: LargeInt;
  175.         FFreeOnDisk: LargeInt;
  176.         FDiskSerial: Integer;
  177.         FDrive: string;
  178.         FHowToDelete: DeleteOpts;
  179.         FTotalSizeToProcess: Cardinal;
  180.         FDiskNr: Integer;
  181.         FTotalDisks: Integer;
  182.         FFileSize: Integer;
  183.         FRealFileSize: Cardinal;
  184.         FWrongZipStruct: Boolean;
  185.         FInFileName: string;
  186.         FInFileHandle: Integer;
  187.         FOutFileHandle: Integer;
  188.         FVersionMadeBy1: Integer;
  189.         FVersionMadeBy0: Integer;
  190.         FDateStamp: Integer; { DOS formatted date/time - use Delphi's
  191.         FileDateToDateTime function to give you TDateTime format.}
  192. fFromDate: TDate;
  193.         FTempDir: string;
  194.         FShowProgress: Boolean;
  195.         FFreeOnDisk1: Integer;
  196.         FMaxVolumeSize: Integer;
  197.         FMinFreeVolSize: Integer;
  198.         FCodePage: CodePageOpts;
  199.         FZipEOC: Integer;               // End-Of-Central-Dir location
  200.         FZipSOC: Integer;               // Start-Of-Central-Dir location
  201.         FZipComment: string;
  202.         FVersionInfo: string;
  203.         FZipStream: TZipStream;
  204.         FPasswordReqCount: LongWord;
  205.         GAssignPassword: Boolean;
  206.         GModalResult: TModalResult;
  207.         FFSpecArgsExcl: TStrings;
  208.         FUseDirOnlyEntries: Boolean;
  209.         FRootDir: string;
  210.         FCurWaitCount: Integer;
  211.         FSaveCursor: TCursor;
  212.         // Dll related variables
  213.         fMinZipDllVer: integer;         // new 1.70
  214.         fMinUnzDllVer: integer;         // new 1.70
  215.         { Main call to execute a ZIP add or Delete.  This call returns the
  216.           number of files that were sucessfully operated on. }
  217.         ZipDllExec: function(ZipRec: pZipParms): DWord; stdcall;
  218.         GetZipDllVersion: function: DWord; stdcall;
  219.         ZipDllHandle: HWND;
  220.         { Main call to execute a ZIP add or Delete.  This call returns the
  221.           number of files that were sucessfully operated on. }
  222.         UnzDllExec: function(UnZipRec: pUnZipParms): DWord; stdcall;
  223.         GetUnzDllVersion: function: DWord; stdcall;
  224.         UnzDllHandle: HWND;
  225.         ZipParms: pZipParms;            { declare an instance of ZipParms 1 or 2 }
  226.         UnZipParms: pUnZipParms;        { declare an instance of UnZipParms 2 }
  227.         { Event variables }
  228.         FOnDirUpdate: TNotifyEvent;
  229.         FOnProgress: TProgressEvent;
  230.         FOnMessage: TMessageEvent;
  231.         FOnSetNewName: TSetNewNameEvent;
  232.         FOnNewName: TNewNameEvent;
  233.         FOnPasswordError: TPasswordErrorEvent;
  234.         FOnCRC32Error: TCRC32ErrorEvent;
  235.         FOnExtractOverwrite: TExtractOverwriteEvent;
  236.         FOnExtractSkipped: TExtractSkippedEvent;
  237.         FOnCopyZipOverwrite: TCopyZipOverwriteEvent;
  238.         FOnFileComment: TFileCommentEvent;
  239.         {$IFNDEF NO_SPAN}
  240.         fConfirmErase: Boolean;
  241.         FDiskWritten: Integer;
  242.         FDriveNr: Integer;
  243.         FFormatErase: Boolean;          // New 1.70
  244.         FInteger: Integer;
  245.         FNewDisk: Boolean;
  246.         FOnGetNextDisk: TGetNextDiskEvent;
  247.         FOnStatusDisk: TStatusDiskEvent;
  248.         FOutFileName: string;
  249.         FZipDiskAction: TZipDiskAction;
  250.         FZipDiskStatus: TZipDiskStatus;
  251.         {$ENDIF}
  252.         {$IFNDEF NO_SFX}
  253.         FSFXCaption: string;            // dflt='Self-extracting Archive'
  254.         FSFXCommandLine: string;        // dflt=''
  255.         FSFXDefaultDir: string;         // dflt=''
  256.         FSFXIcon: TIcon;
  257.         FSFXMessage: string;
  258.         FSFXOptions: SFXOpts;
  259.         FSFXOverWriteMode: OvrOpts;     // ovrConfirm  (others: ovrAlways, ovrNever)
  260.         FSFXPath: string;
  261.         FJumpValue: array[#0..#255] of Integer;
  262.         {$ENDIF}
  263.         { Property get/set functions }
  264.         function GetCount: Integer;
  265.         procedure SetFSpecArgs(Value: TStrings);
  266.         procedure SetFileName(Value: string);
  267.         function GetZipVers: Integer;
  268.         function GetUnzVers: Integer;
  269.         procedure SetDLLDirectory(Value: string);
  270.         procedure SetVersionInfo(Value: string);
  271.         function GetZipComment: string;
  272.         procedure SetZipComment(zComment: string);
  273.         procedure SetPasswordReqCount(Value: LongWord);
  274.         procedure SetFSpecArgsExcl(Value: TStrings);
  275.         { Private "helper" functions }
  276.         function Load_ZipDll(var autoload: boolean): integer; // new 1.70
  277.         function Load_UnzDll(var autoload: boolean): integer; // new 1.70
  278.         procedure SetMinZipDllVers(Value: integer); // New 1.70
  279.         procedure SetMinUnzDllVers(Value: integer); // New 1.70
  280.         function GetDirEntry(idx: integer): ZipDirEntry; // New 1.70
  281.         function GetZipDllPath(handle: cardinal): string; // New 1.70
  282.         function GetUnzDllPath(handle: cardinal): string; // New 1.70
  283.         procedure FreeZipDirEntryRecords;
  284.         procedure SetZipSwitches(var NameOfZipFile: string; zpVersion: Integer);
  285.         procedure SetUnZipSwitches(var NameOfZipFile: string; uzpVersion: Integer);
  286.         procedure ShowExceptionError(const ZMExcept: EZipMaster);
  287.         function LoadZipStr(Ident: Integer; DefaultStr: string): string;
  288.         function ConvCodePage(Source: string; Direction: CodePageDirection): string;
  289.         function IsDiskPresent: Boolean;
  290.         function CheckIfLastDisk(var EOC: ZipEndOfCentral; DoExcept: Boolean): Boolean;
  291.         function ReplaceForwardSlash(aStr: string): string;
  292.         function CopyBuffer(InFile, OutFile, ReadLen: Integer): Integer;
  293.         procedure WriteJoin(Buffer: pChar; BufferSize, DSErrIdent: Integer);
  294.         procedure GetNewDisk(DiskSeq: Integer);
  295.         procedure DiskFreeAndSize(Action: Integer);
  296.         procedure AddSuffix(const SufOption: AddStoreSuffixEnum; var sStr: string; sPos: Integer);
  297.         procedure ExtExtract(UseStream: Integer; MemStream: TMemoryStream);
  298. procedure ExtAdd(UseStream: Integer; StrFileDate, StrFileAttr: DWORD; MemStream: TMemoryStream);
  299.         procedure SetDeleteSwitches;
  300.         procedure StartWaitCursor;
  301.         procedure StopWaitCursor;
  302.         procedure TraceMessage(Msg: string);
  303.         // procedure DoOnMessage(Sender: TObject; ErrCode: Integer; Message: string); // New 1.70
  304.         {$IFNDEF NO_SPAN}
  305.         function CheckForDisk: Integer;
  306.         procedure ClearFloppy(dir: string); // New 1.70
  307.         function IsRightDisk(drt: Integer): Boolean;
  308.         function MakeString(Buffer: pChar; Size: Integer): string;
  309.         procedure RWJoinData(Buffer: pChar; ReadLen, DSErrIdent: Integer);
  310.         procedure RWSplitData(Buffer: pChar; ReadLen, ZSErrVal: Integer);
  311.         procedure WriteSplit(Buffer: pChar; Len: Integer; MinSize: Integer);
  312.         function ZipFormat: Integer;    // New 1.70
  313.         {$ENDIF}
  314.         {$IFNDEF NO_SFX}
  315.         function IsInstallShield(const fh: THandle): Boolean;
  316.         function ReplaceIcon(SFXFile, SFXSize: Integer): Integer;
  317.         function RWCentralDir(OutFile: Integer; EOC: ZipEndOfCentral; OffsetChange: Integer): Integer;
  318.         procedure SetSFXIcon(aIcon: TIcon);
  319.         {$ENDIF}
  320.     public
  321.         constructor Create(AOwner: TComponent); override;
  322.         destructor Destroy; override;
  323.         { Public Properties (run-time only) }
  324.         property Handle: HWND read fHandle write fHandle;
  325.         property ErrCode: Integer read fErrCode write fErrCode;
  326.         property Message: string read fMessage write fMessage;
  327.         property ZipContents: TList read FZipContents;
  328.         property Cancel: Boolean read fCancel write fCancel;
  329.         property ZipBusy: Boolean read fZipBusy;
  330.         property UnzBusy: Boolean read fUnzBusy;
  331.         property Count: Integer read GetCount;
  332.         property SuccessCnt: Integer read FSuccessCnt;
  333.         property ZipVers: Integer read GetZipVers;
  334.         property UnzVers: Integer read GetUnzVers;
  335.         property SFXOffset: Integer read FSFXOffset;
  336.         property ZipSOC: Integer read FZipSOC default 0;
  337.         property ZipEOC: Integer read FZipEOC default 0;
  338.         property IsSpanned: Boolean read FIsSpanned default False;
  339.         property ZipFileSize: Cardinal read FRealFileSize default 0;
  340.         property FullErrCode: Integer read FFullErrCode;
  341.         property TotalSizeToProcess: Cardinal read FTotalSizeToProcess;
  342.         property ZipComment: string read GetZipComment write SetZipComment;
  343.         property ZipStream: TZipStream read FZipStream;
  344.         property DirOnlyCount: Integer read FDirOnlyCount default 0;
  345.         { Public Methods }
  346.         { NOTE: Test is an sub-option of extract }
  347.         procedure Add;
  348.         procedure Delete;
  349.         procedure Extract;
  350.         procedure List;
  351.         // load dll - return version
  352.         function Load_Zip_Dll: integer;
  353.         function Load_Unz_Dll: integer;
  354.         procedure Unload_Zip_Dll;
  355.         procedure Unload_Unz_Dll;
  356.         procedure AbortDlls;
  357.         function CopyFile(const InFileName, OutFileName: string): Integer;
  358.         function EraseFile(const Fname: string; How: DeleteOpts): Integer;
  359.         function GetAddPassword: string;
  360.         function GetExtrPassword: string;
  361.         function AppendSlash(sDir: string): string;
  362.         { New in v1.6 }
  363.         function Rename(RenameList: TList; DateTime: Integer): Integer;
  364.         function ExtractFileToStream(Filename: string): TZipStream;
  365.         function AddStreamToStream(InStream: TMemoryStream): TZipStream;
  366.         {$IFDEF VERD4+}
  367.         function ExtractStreamToStream(InStream: TMemoryStream; OutSize: LongWord = 32768): TZipStream;
  368.         procedure AddStreamToFile(Filename: string = ''; FileDate: DWord = 0; FileAttr: DWord = 0);
  369.         function MakeTempFileName(Prefix: string = 'zip'; Extension: string = '.zip'): string;
  370.         procedure ShowZipMessage(Ident: Integer; UserStr: string = '');
  371.         {$ELSE}
  372.         procedure AddStreamToFile(Filename: string; FileDate, FileAttr: Dword);
  373.         function ExtractStreamToStream(InStream: TMemoryStream; OutSize: Longword): TZipStream;
  374.         function MakeTempFileName(Prefix, Extension: string): string;
  375.         procedure ShowZipMessage(Ident: Integer; UserStr: string);
  376.         {$ENDIF}
  377.         function GetPassword(DialogCaption, MsgTxt: string; pwb: TPasswordButtons; var ResultStr: string): TPasswordButton;
  378.         function CopyZippedFiles(DestZipMaster: TZipMaster; DeleteFromSource: boolean; OverwriteDest: OvrOpts): Integer;
  379.         property DirEntry[idx: integer]: ZipDirEntry read GetDirEntry; // New 1.70
  380.         function FullVersionString: string; // New 1.70
  381.         {$IFNDEF NO_SPAN}
  382.         function ReadSpan(InFileName: string; var OutFilePath: string): Integer;
  383.         function WriteSpan(InFileName, OutFileName: string): Integer;
  384.         {$ENDIF}
  385.         {$IFNDEF NO_SFX}
  386.         function ConvertSFX: Integer;
  387.         function ConvertZIP: Integer;
  388.         function IsZipSFX(const SFXExeName: string): Integer;
  389.         {$ENDIF}
  390.     published
  391.         { Public properties that also show on Object Inspector }
  392.         property Verbose: Boolean read FVerbose
  393.             write FVerbose;
  394.         property Trace: Boolean read FTrace
  395.             write FTrace;
  396.         property AddCompLevel: Integer read FAddCompLevel
  397.             write FAddCompLevel;
  398.         property AddOptions: AddOpts read FAddOptions
  399. write fAddOptions;
  400. property AddFrom: TDate read fFromDate write fFromDate;
  401.         property ExtrBaseDir: string read FExtrBaseDir
  402.             write FExtrBaseDir;
  403.         property ExtrOptions: ExtrOpts read FExtrOptions
  404.             write FExtrOptions;
  405.         property FSpecArgs: TStrings read FFSpecArgs
  406.             write SetFSpecArgs;
  407.         property Unattended: Boolean read FUnattended
  408.             write FUnattended;
  409.         { At runtime: every time the filename is assigned a value,
  410.           the ZipDir will automatically be read. }
  411.         property ZipFileName: string read FZipFileName
  412.             write SetFileName;
  413.         property Password: ShortString read FPassword
  414.             write FPassword;
  415.         property DLLDirectory: string read FDLLDirectory
  416.             write SetDLLDirectory;
  417.         property MinZipDllVers: integer read fMinZipDllVer
  418.             write SetMinZipDllVers;     // default Min_ZipDll_Vers; // new 1.70
  419.         property MinUnzDllVers: integer read fMinUnzDllVer
  420.             write SetMinUnzDllVers;     // default Min_UnzDll_Vers; // new 1.70
  421.         property TempDir: string read FTempDir
  422.             write FTempDir;
  423.         property CodePage: CodePageOpts read FCodePage
  424.             write FCodePage default cpAuto;
  425.         property HowToDelete: DeleteOpts read FHowToDelete
  426.             write FHowToDelete default htdAllowUndo;
  427.         { New in 1.52k }
  428.         property VersionInfo: string read FVersionInfo
  429.             write SetVersionInfo;
  430.         { New in v1.6 }
  431.         property AddStoreSuffixes: AddStoreExts read FAddStoreSuffixes
  432.             write FAddStoreSuffixes;
  433.         property PasswordReqCount: LongWord read FPasswordReqCount
  434.             write SetPasswordReqCount default 1;
  435.         property FSpecArgsExcl: TStrings read FFSpecArgsExcl
  436.             write SetFSpecArgsExcl;
  437.         property UseDirOnlyEntries: Boolean read FUseDirOnlyEntries
  438.             write FUseDirOnlyEntries default False;
  439.         property RootDir: string read FRootDir
  440.             write fRootDir;
  441.         { Events }
  442.         property OnDirUpdate: TNotifyEvent read FOnDirUpdate
  443.             write FOnDirUpdate;
  444.         property OnProgress: TProgressEvent read FOnProgress
  445.             write FOnProgress;
  446.         property OnMessage: TMessageEvent read fOnMessage write fOnMessage;
  447.         { New in v1.6 }
  448.         property OnSetNewName: TSetNewNameEvent read FOnSetNewName
  449.             write FOnSetNewName;
  450.         property OnNewName: TNewNameEvent read FOnNewName
  451.             write FOnNewName;
  452.         property OnCRC32Error: TCRC32ErrorEvent read FOnCRC32Error
  453.             write FOnCRC32Error;
  454.         property OnPasswordError: TPasswordErrorEvent read FOnPasswordError
  455.             write FOnPasswordError;
  456.         property OnExtractOverwrite: TExtractOverwriteEvent read FOnExtractOverwrite
  457.             write FOnExtractOverwrite;
  458.         property OnExtractSkipped: TExtractSkippedEvent read FOnExtractSkipped
  459.             write FOnExtractSkipped;
  460.         property OnCopyZipOverwrite: TCopyZipOverwriteEvent read FOnCopyZipOverwrite
  461.             write FOnCopyZipOverwrite;
  462.         property OnFileComment: TFileCommentEvent read FOnFileComment
  463.             write FOnFileComment;
  464.         {$IFNDEF NO_SPAN}
  465.         property ConfirmErase: Boolean read fConfirmErase write fConfirmErase default True;
  466.         property FormatErase: Boolean read FFormatErase write FFormatErase default False;
  467.         property KeepFreeOnDisk1: Integer read FFreeOnDisk1 write FFreeOnDisk1;
  468.         property MaxVolumeSize: Integer read FMaxVolumeSize write FMaxVolumesize default 0;
  469.         property MinFreeVolumeSize: Integer read FMinFreeVolSize write FMinFreeVolSize default 65536;
  470.         property OnGetNextDisk: TGetNextDiskEvent read FOnGetNextDisk write FOnGetNextDisk;
  471.         property OnStatusDisk: TStatusDiskEvent read FOnStatusDisk write FOnStatusDisk;
  472.         {$ENDIF}
  473.         {$IFNDEF NO_SFX}
  474.         property SFXCaption: string read FSFXCaption write FSFXCaption;
  475.         property SFXCommandLine: string read FSFXCommandLine write FSFXCommandLine;
  476.         property SFXDefaultDir: string read FSFXDefaultDir write FSFXDefaultDir;
  477.         property SFXIcon: TIcon read FSFXIcon write SetSFXIcon;
  478.         property SFXMessage: string read FSFXMessage write FSFXMessage;
  479.         property SFXOptions: SfxOpts read FSFXOptions write FSFXOptions default [SFXCheckSize];
  480.         property SFXOverWriteMode: OvrOpts read FSFXOverWriteMode write FSFXOverWriteMode;
  481.         property SFXPath: string read FSFXPath write FSFXPath;
  482.         {$ENDIF}
  483.     end;
  484. function PathConcat(path, extra: string): string;
  485. procedure Register;
  486. implementation
  487. uses ZipStructs;
  488. {$R ZipMstr.Res}
  489. const                                   { these are stored in reverse order }
  490.     LocalFileHeaderSig = $04034B50;     { 'PK'34  (in file: 504b0304) }
  491.     CentralFileHeaderSig = $02014B50;   { 'PK'12 }
  492.     EndCentralDirSig = $06054B50;       { 'PK'56 }
  493.     ExtLocalSig = $08074B50;            { 'PK'78 }
  494.     BufSize = 8192;                     // Keep under 12K to avoid Winsock problems on Win95.
  495.     // If chunks are too large, the Winsock stack can
  496.     // lose bytes being sent or received.
  497.     FlopBufSize = 65536;
  498.     RESOURCE_ERROR: string = 'ZipMsgXX.res is probably not linked to the executable' + #10 + 'Missing String ID is: ';
  499.     ZIPVERSION = 170;
  500.     UNZIPVERSION = 170;
  501. type
  502.     TBuffer = array[0..BufSize - 1] of Byte;
  503.     pBuffer = ^TBuffer;
  504.     { Define the functions that are not part of the TZipMaster class. }
  505.     { The callback function must NOT be a member of a class. }
  506.     { We use the same callback function for ZIP and UNZIP. }
  507. function ZCallback(ZCallBackRec: pZCallBackStruct): LongBool; stdcall; export; forward;
  508. type
  509.     TPasswordDlg = class(TForm)
  510.     private
  511.         PwBtn: array[0..3] of TBitBtn;
  512.         PwdEdit: TEdit;
  513.         PwdTxt: TLabel;
  514.     public
  515.         constructor CreateNew2(Owner: TComponent; pwb: TPasswordButtons); virtual;
  516.         destructor Destroy; override;
  517.         function ShowModalPwdDlg(DlgCaption, MsgTxt: string): string; virtual;
  518.     end;
  519. type
  520.     MDZipData = record                  // MyDirZipData
  521.         Diskstart: Word;                // The disk number where this file begins
  522.         RelOffLocal: LongWord;          // offset from the start of the first disk
  523.         FileNameLen: Word;              // length of current filename
  524.         FileName: array[0..254] of Char; // Array of current filename
  525.         CRC32: LongWord;
  526.         ComprSize: LongWord;
  527.         UnComprSize: LongWord;
  528.         DateTime: Integer;
  529.     end;
  530.     pMZipData = ^MDZipData;
  531.     TMZipDataList = class(TList)
  532.     private
  533.         function GetItems(Index: integer): pMZipData;
  534.     public
  535.         constructor Create(TotalEntries: integer);
  536.         destructor Destroy; override;
  537.         property Items[Index: integer]: pMZipData read GetItems;
  538.         function IndexOf(fname: string): integer;
  539.     end;
  540.     // ==================================================================
  541.     {$IFDEF VER90}                      // if Delphi 2
  542. function AnsiStrPos(S1, S2: pChar): pChar;
  543. begin
  544.     Result := StrPos(S1, S2);           // not will not work with MBCS
  545. end;
  546. function AnsiStrIComp(S1, S2: pChar): Integer;
  547. begin
  548.     Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, S1, -1, S2, -1) - 2;
  549. end;
  550. function AnsiPos(const Substr, S: string): Integer;
  551. begin
  552.     Result := Pos(Substr, S);
  553. end;
  554. {$ENDIF}
  555. // ---------------------------- ZipDataList --------------------------------
  556. function TMZipDataList.GetItems(Index: integer): pMZipData;
  557. begin
  558.     if Index >= Count then
  559.         raise Exception.CreateFmt('Index (%d) outside range 1..%d',
  560.             [Index, Count - 1]);
  561.     Result := inherited Items[Index];
  562. end;
  563. constructor TMZipDataList.Create(TotalEntries: integer);
  564. var
  565.     i: Integer; MDZDp: pMZipData;
  566. begin
  567.     inherited Create;
  568.     Capacity := TotalEntries;
  569.     for i := 1 to TotalEntries do
  570.     begin
  571.         New(MDZDp);
  572.         MDZDp^.FileName := '';
  573.         Add(MDZDp);
  574.     end;
  575. end;
  576. destructor TMZipDataList.Destroy;
  577. var
  578.     i: Integer; MDZDp: pMZipData;
  579. begin
  580.     if Count > 0 then
  581.     begin
  582.         for i := (Count - 1) downto 0 do
  583.         begin
  584.             MDZDp := Items[i];
  585.             if Assigned(MDZDp) then     // dispose of the memory pointed-to by this entry
  586.                 Dispose(MDZDp);
  587.             Delete(i);                  // delete the TList pointer itself
  588.         end;
  589.     end;
  590.     inherited Destroy;
  591. end;
  592. function TMZipDataList.IndexOf(fname: string): integer;
  593. var
  594.     MDZDp: pMZipData;
  595. begin
  596.     for Result := 0 to (Count - 1) do
  597.     begin
  598.         MDZDp := Items[Result];
  599.         if CompareText(fname, MDZDp^.FileName) = 0 then // case insensitive compare
  600.             break;
  601.     end;
  602.     // Should not happen, but maybe in a bad archive...
  603.     if Result = Count then
  604.         raise EZipMaster.CreateResDisp(DS_EntryLost, True);
  605. end;
  606. //----------------------------------------------------------------------------
  607. { Dennis Passmore (Compuserve: 71640,2464) contributed the idea of passing an
  608.   instance handle to the DLL, and, in turn, getting it back from the callback.
  609.   This lets us referance variables in the TZipMaster class from within the
  610.   callback function.  Way to go Dennis! }
  611. function ZCallback(ZCallBackRec: PZCallBackStruct): LongBool; stdcall; export;
  612. var
  613.     Msg, OldFileName, pwd, FileComment: string;
  614.     IsChanged, DoExtract, DoOverwrite: Boolean;
  615.     RptCount: LongWord;
  616.     Action: TPasswordButton;
  617. begin
  618.     with ZCallBackRec^, (TObject(Caller) as TZipMaster) do
  619.     begin
  620.         Msg := ReplaceForwardSlash(TrimRight(FileNameOrMsg));
  621.         case ActionCode of
  622.             1:                          { progress type 1 = starting any ZIP operation on a new file }
  623.                 if Assigned(FOnProgress) then
  624.                     FOnProgress(Caller, NewFile, Msg, FileSize);
  625.             2:                          { progress type 2 = increment bar }
  626.                 if Assigned(FOnProgress) then
  627.                     FOnProgress(Caller, ProgressUpdate, '', FileSize);
  628.             3:                          { end of a batch of 1 or more files }
  629.                 if Assigned(FOnProgress) then
  630.                     FOnProgress(Caller, EndOfBatch, '', 0);
  631.             4:                          { a routine status message }
  632.                 begin
  633.                     Message := Msg;
  634.                     if ErrorCode <> 0 then // W'll always keep the last ErrorCode
  635.                     begin
  636.                         ErrCode := Integer(Char(ErrorCode and $FF));
  637.                         fFullErrCode := ErrorCode;
  638.                     end;
  639.                     if Assigned(OnMessage) then
  640.                         OnMessage(Caller, ErrorCode, Msg);
  641.                 end;
  642.             5:                          { total number of files to process }
  643.                 if Assigned(OnProgress) then
  644.                     OnProgress(Caller, TotalFiles2Process, '', FileSize);
  645.             6:                          { total size of all files to be processed }
  646.                 begin
  647.                     FTotalSizeToProcess := FileSize;
  648.                     if Assigned(FOnProgress) then
  649.                         FOnProgress(Caller, TotalSize2Process, '', FileSize);
  650.                 end;
  651.             7:                          { new in v1.60, request for a new path+name just before zipping or extracting }
  652.                 if Assigned(FOnSetNewName) then
  653.                 begin
  654.                     OldFileName := Msg;
  655.                     IsChanged := False;
  656.                     FOnSetNewName(Caller, OldFileName, IsChanged);
  657.                     if IsChanged then
  658.                     begin
  659.                         StrPLCopy(FileNameOrMsg, OldFileName, 512);
  660.                         ErrorCode := 1;
  661.                     end
  662.                     else
  663.                         ErrorCode := 0;
  664.                 end;
  665.             8:                          { New or other password needed during Extract() }
  666.                 begin
  667.                     pwd := '';
  668.                     RptCount := FileSize;
  669.                     Action := pwbOk;
  670.                     GAssignPassword := False;
  671.                     if Assigned(FOnPasswordError) then
  672.                     begin
  673.                         GModalResult := mrNone;
  674.                         FOnPasswordError(Caller, IsOperationZip, pwd, Msg, RptCount, Action);
  675.                         if Action <> pwbOk then
  676.                             pwd := '';
  677.                         if Action = pwbCancelAll then
  678.                             GModalResult := mrNoToAll;
  679.                         if Action = pwbAbort then
  680.                             GModalResult := mrAbort;
  681.                     end
  682.                     else
  683.                         if (ErrorCode and $01) <> 0 then
  684.                             pwd := GetAddPassword()
  685.                         else
  686.                             pwd := GetExtrPassword();
  687.                     if pwd <> '' then
  688.                     begin
  689.                         StrPLCopy(FileNameOrMsg, pwd, PWLEN);
  690.                         ErrorCode := 1;
  691.                     end
  692.                     else
  693.                     begin
  694.                         RptCount := 0;
  695.                         ErrorCode := 0;
  696.                     end;
  697.                     if RptCount > 15 then
  698.                         FileSize := 15
  699.                     else
  700.                         FileSize := RptCount;
  701.                     if GModalResult = mrNoToAll then // Cancel all
  702.                         ActionCode := 0;
  703.                     if GModalResult = mrAbort then // Abort
  704.                         Cancel := True;
  705.                     GAssignPassword := True;
  706.                 end;
  707.             9:                          { CRC32 error, (default action is extract/test the file) }
  708.                 begin
  709.                     DoExtract := true;  // This was default for versions <1.6
  710.                     if Assigned(FOnCRC32Error) then
  711.                         FOnCRC32Error(Caller, Msg, ErrorCode, FileSize, DoExtract);
  712.                     ErrorCode := Integer(DoExtract);
  713.                     { This will let the Dll know it should send some warnings }
  714.                     if not Assigned(FOnCRC32Error) then
  715.                         ErrorCode := 2;
  716.                 end;
  717.             10:                         { Extract(UnZip) Overwrite ask }
  718.                 if Assigned(FOnExtractOverwrite) then
  719.                 begin
  720.                     DoOverwrite := Boolean(FileSize);
  721.                     FOnExtractOverwrite(Caller, Msg, (ErrorCode and $10000) = $10000, DoOverwrite, ErrorCode and $FFFF);
  722.                     FileSize := Integer(DoOverwrite);
  723.                 end;
  724.             11:                         { Extract(UnZip) and Skipped }
  725.                 begin
  726.                     if ErrorCode <> 0 then
  727.                     begin
  728.                         ErrCode := Integer(Char(ErrorCode and $FF));
  729.                         FFullErrCode := ErrorCode;
  730.                     end;
  731.                     if Assigned(FOnExtractSkipped) then
  732.                         //FOnExtractSkipped( Caller, Msg, UnZipSkipTypes(FileSize), ErrorCode );
  733.                         FOnExtractSkipped(Caller, Msg, UnZipSkipTypes((FileSize and $FF) - 1), ErrorCode);
  734.                 end;
  735.             12:                         { Add(Zip) FileComments. v1.60L }
  736.                 if Assigned(FOnFileComment) then
  737.                 begin
  738.                     FileComment := FileNameOrMsg[256];
  739.                     IsChanged := False;
  740.                     FOnFileComment(Caller, Msg, FileComment, IsChanged);
  741.                     if IsChanged and (FileComment <> '') then
  742.                         StrPLCopy(FileNameOrMsg, FileComment, 511)
  743.                     else
  744.                         FileNameOrMsg[0] := #0;
  745.                     ErrorCode := Integer(IsChanged);
  746.                     FileSize := Length(FileComment);
  747.                     if FileSize > 511 then
  748.                         FileSize := 511;
  749.                 end;
  750.             13:                         { Stream2Stream extract. v1.60M }
  751.                 begin
  752.                     try
  753.                         FZipStream.SetSize(FileSize);
  754.                     except
  755.                         ErrorCode := 1;
  756.                         FileSize := 0;
  757.                     end;
  758.                     if ErrorCode <> 1 then
  759.                         FileSize := Integer(FZipStream.Memory);
  760.                 end;
  761.         end;                            {end case }
  762.         { If you return TRUE, then the DLL will abort it's current
  763.           batch job as soon as it can. }
  764.         Result := Cancel;
  765.     end;                                { end with }
  766.     Application.ProcessMessages;
  767. end;
  768. { Implementation of TZipMaster class member functions }
  769. {-----------------------------------------------------}
  770. constructor TZipMaster.Create(AOwner: TComponent);
  771. begin
  772.     inherited Create(AOwner);
  773.     fZipContents := TList.Create;
  774.     FFSpecArgs := TStringList.Create;
  775.     FFSpecArgsExcl := TStringList.Create; { New in v1.6 }
  776.     fHandle := Application.Handle;
  777.     ZipParms {.zp1} := nil;
  778.     UnZipParms := nil;
  779.     FZipFileName := '';
  780.     FPassword := '';
  781.     FPasswordReqCount := 1;             { New in v1.6 }
  782.     FEncrypt := False;
  783.     FSuccessCnt := 0;
  784.     FAddCompLevel := 9;                 { dflt to tightest compression }
  785.     FDLLDirectory := '';
  786.     AutoExeViaAdd := False;
  787.     FUnattended := False;
  788.     FRealFileSize := 0;
  789.     FSFXOffset := 0;
  790.     FZipSOC := 0;
  791.     FFreeOnDisk1 := 0;                  { Don't leave any freespace on disk 1. }
  792.     FMaxVolumeSize := 0;                { Use the maximum disk size. }
  793.     FMinFreeVolSize := 65536;           { Reject disks with less free bytes than... }
  794.     FCodePage := cpAuto;
  795.     FIsSpanned := False;
  796.     FZipComment := '';
  797.     HowToDelete := htdAllowUndo;
  798.     FAddStoreSuffixes := [assGIF, assPNG, assZ, assZIP, assZOO, assARC, assLZH, assARJ, assTAZ, assTGZ, assLHA, assRAR, assACE, assCAB, assGZ, assGZIP, assJAR];
  799.     FZipStream := TZipStream.Create;
  800.     FUseDirOnlyEntries := False;
  801.     FDirOnlyCount := 0;
  802.     FVersionInfo := ZIPMASTERVERSION;
  803.     FCurWaitCount := 0;
  804.     ZipDllHandle := 0;
  805.     UnzDllHandle := 0;
  806.     fMinZipDllVer := Min_ZipDll_Vers;   // new 1.70
  807.     fMinUnzDllVer := Min_UnzDll_Vers;   // new 1.70
  808.     {$IFNDEF NO_SPAN}
  809.     fFormatErase := False;
  810.     fConfirmErase := True;
  811.     {$ENDIF}
  812.     {$IFNDEF NO_SFX}
  813.     FSFXIcon := TIcon.Create;           { New in v1.6 }
  814.     FSFXOverWriteMode := ovrConfirm;
  815.     FSFXCaption := 'Self-extracting Archive';
  816.     FSFXDefaultDir := '';
  817.     FSFXCommandLine := '';
  818.     FSFXOptions := [SFXCheckSize];      { Select this opt by default. }
  819.     FSFXPath := 'ZipSFX.bin';
  820.     {$ENDIF}
  821. end;
  822. destructor TZipMaster.Destroy;
  823. begin
  824.     Unload_Zip_Dll;
  825.     Unload_Unz_Dll;
  826.     FZipStream.Free;
  827.     FreeZipDirEntryRecords;
  828.     fZipContents.Free;
  829.     FFSpecArgsExcl.Free;
  830.     FFSpecArgs.Free;
  831.     {$IFNDEF NO_SPAN}
  832.     {$ENDIF}
  833.     {$IFNDEF NO_SFX}
  834.     FSFXIcon.Free;
  835.     {$ENDIF}
  836.     inherited Destroy;
  837. end;
  838. function TPasswordDlg.ShowModalPwdDlg(DlgCaption, MsgTxt: string): string;
  839. begin
  840.     Caption := DlgCaption;
  841.     PwdTxt.Caption := MsgTxt;
  842.     ShowModal();
  843.     if ModalResult = mrOk then
  844.         Result := PwdEdit.Text
  845.     else
  846.         Result := '';
  847. end;
  848. constructor TPasswordDlg.CreateNew2(Owner: TComponent; pwb: TPasswordButtons);
  849. var
  850.     BtnCnt, Btns, i, k: Integer;
  851. begin
  852.     inherited CreateNew(Owner{$IFDEF VERD4+}, 0{$ENDIF});
  853.     // Convert Button Set to a bitfield
  854.     BtnCnt := 1;                        // We need at least the Ok button
  855.     Btns := 1;
  856.     if pwbCancel in pwb then
  857.     begin
  858.         Inc(BtnCnt);
  859.         Btns := Btns or 2;
  860.     end;
  861.     if pwbCancelAll in pwb then
  862.     begin
  863.         Inc(BtnCnt);
  864.         Btns := Btns or 4;
  865.     end;
  866.     if pwbAbort in pwb then
  867.     begin
  868.         Inc(BtnCnt);
  869.         Btns := Btns or 8;
  870.     end;
  871.     Parent := Self;
  872.     Width := 124 * BtnCnt + 35;
  873.     Height := 137;
  874.     Font.Name := 'Arial';
  875.     Font.Height := -12;
  876.     Font.Style := Font.Style + [fsBold];
  877.     BorderStyle := bsDialog;
  878.     Position := poScreenCenter;
  879.     PwdTxt := TLabel.Create(Self);
  880.     PwdTxt.Parent := Self;
  881.     PwdTxt.Left := 20;
  882.     PwdTxt.Top := 8;
  883.     PwdTxt.Width := 297;
  884.     PwdTxt.Height := 18;
  885.     PwdTxt.AutoSize := False;
  886.     PwdEdit := TEdit.Create(Self);
  887.     PwdEdit.Parent := Self;
  888.     PwdEdit.Left := 20;
  889.     PwdEdit.Top := 40;
  890.     PwdEdit.Width := 124 * BtnCnt - 10;
  891.     PwdEdit.PasswordChar := '*';
  892.     PwdEdit.MaxLength := PWLEN;
  893.     for i := 1 to 3 do
  894.         PwBtn[i] := nil;
  895.     k := 0;
  896.     for i := 1 to 8 do
  897.     begin
  898.         if (i = 3) or ((i > 4) and (i < 8)) then
  899.             Continue;
  900.         if (Btns and i) = 0 then
  901.             Continue;
  902.         PwBtn[k] := TBitBtn.Create(Self);
  903.         PwBtn[k].Parent := Self;
  904.         PwBtn[k].Top := 72;
  905.         PwBtn[k].Height := 28;
  906.         PwBtn[k].Width := 114;
  907.         PwBtn[k].Left := 20 + 124 * k;
  908.         case i of
  909.             1: PwBtn[k].Kind := bkOk;
  910.             2: PwBtn[k].Kind := bkCancel;
  911.             4: PwBtn[k].Kind := bkNo;
  912.             8: PwBtn[k].Kind := bkAbort;
  913.         end;
  914.         if i = 4 then
  915.             PwBtn[k].ModalResult := mrNoToAll;
  916.         case i of
  917.             1: PwBtn[k].Caption := LoadStr(PW_Ok);
  918.             2: PwBtn[k].Caption := LoadStr(PW_Cancel);
  919.             4: PwBtn[k].Caption := LoadStr(PW_CancelAll);
  920.             8: PwBtn[k].Caption := LoadStr(PW_Abort);
  921.         end;
  922.         Inc(k);
  923.     end;
  924. end;
  925. destructor TPasswordDlg.Destroy;
  926. var
  927.     i: Integer;
  928. begin
  929.     for i := 0 to 3 do
  930.         PwBtn[i].Free;
  931.     PwdEdit.Free;
  932.     PwdTxt.Free;
  933.     inherited Destroy;
  934. end;
  935. // defaults if old resource used
  936. function LoadZipMsg(Ident: Integer): string;
  937. begin
  938.     case Ident of
  939.         LZ_OldZipDll: Result := 'Old Dll from ';
  940.         LU_OldUnzDll: Result := 'Old Dll from ';
  941.         SF_NOSFXSupport: Result := 'SFX not supported';
  942.         DS_NoDiskSpan: Result := 'Span not supported';
  943.     else
  944.         Result := RESOURCE_ERROR + IntToStr(Ident);
  945.     end;
  946. end;
  947. procedure TZipMaster.ShowZipMessage(Ident: Integer; UserStr: string);
  948. var
  949.     Msg: string;
  950. begin
  951.     //    Msg := LoadZipStr(Ident, RESOURCE_ERROR + IntToStr(Ident)) + UserStr;
  952.     Msg := LoadStr(Ident);
  953.     if Msg = '' then
  954.         Msg := LoadZipMsg(Ident);
  955.     Msg := Msg + UserStr;
  956.     Message := Msg;
  957.     ErrCode := Ident;
  958.     if FUnattended = False then
  959.         ShowMessage(Msg);
  960.     if Assigned(OnMessage) then
  961.         OnMessage(Self, 0, Msg);        // No ErrCode here else w'll get a msg from the application
  962. end;
  963. function TZipMaster.LoadZipStr(Ident: Integer; DefaultStr: string): string;
  964. begin
  965.     Result := LoadStr(Ident);
  966.     if Result = '' then
  967.         Result := DefaultStr;
  968. end;
  969. procedure TZipMaster.TraceMessage(Msg: string);
  970. begin
  971.     if Trace and Assigned(OnMessage) then
  972.         OnMessage(Self, 0, Msg);        // No ErrCode here else w'll get a msg from the application
  973. end;
  974. //---------------------------------------------------------------------------
  975. // Somewhat different from ShowZipMessage() because the loading of the resource
  976. // string is already done in the constructor of the exception class.
  977. procedure TZipMaster.ShowExceptionError(const ZMExcept: EZipMaster);
  978. begin
  979.     if (ZMExcept.FDisplayMsg = True) and (Unattended = False) then
  980.         ShowMessage(ZMExcept.Message);
  981.     ErrCode := ZMExcept.FResIdent;
  982.     Message := ZMExcept.Message;
  983.     if Assigned(OnMessage) then
  984.         OnMessage(Self, 0, ZMExcept.Message);
  985. end;
  986. {  Convert filename (and file comment string) into "internal" charset (ISO).
  987.  * This function assumes that Zip entry filenames are coded in OEM (IBM DOS)
  988.  * codepage when made on:
  989.  *  -> DOS (this includes 16-bit Windows 3.1) (FS_FAT_  0 )
  990.  *  -> OS/2                                   (FS_HPFS_ 6 )
  991.  *  -> Win95/WinNT with Nico Mak's WinZip     (FS_NTFS_ 11 && hostver == "5.0" 50)
  992.  *
  993.  * All other ports are assumed to code zip entry filenames in ISO 8859-1.
  994.  *
  995.  * NOTE: Norton Zip v1.0 sets the host byte incorrectly. In this case you need
  996.  * to set the CodePage property manually to cpOEM to force the conversion.
  997. }
  998. function TZipMaster.ConvCodePage(Source: string; Direction: CodePageDirection): string;
  999. const
  1000.     FS_FAT: Integer = 0;
  1001.     FS_HPFS: Integer = 6;
  1002.     FS_NTFS: Integer = 11;
  1003. var
  1004.     i: Integer;
  1005. begin
  1006.     SetLength(Result, Length(Source));
  1007.     if ((FCodePage = cpAuto) and (FVersionMadeBy1 = FS_FAT) or (FVersionMadeBy1 = FS_HPFS)
  1008.         or ((FVersionMadeBy1 = FS_NTFS) and (FVersionMadeBy0 = 50))) or (FCodePage = cpOEM) then
  1009.     begin
  1010.         for i := 1 to Length(Source) do
  1011.             if Char(Source[i]) < Char($80) then
  1012.                 Result[i] := Source[i]
  1013.             else
  1014.                 if Direction = cpdOEM2ISO then
  1015.                     OemToCharBuff(@Source[i], @Result[i], 1)
  1016.                 else
  1017.                     CharToOemBuff(@Source[i], @Result[i], 1)
  1018.     end
  1019.     else
  1020.         Result := Source;
  1021. end;
  1022. { We'll normally have a TStringList value, since TStrings itself is an
  1023.   abstract class. }
  1024. procedure TZipMaster.SetFSpecArgs(Value: TStrings);
  1025. begin
  1026.     FFSpecArgs.Assign(Value);
  1027. end;
  1028. procedure TZipMaster.SetFSpecArgsExcl(Value: TStrings);
  1029. begin
  1030.     FFSpecArgsExcl.Assign(Value);
  1031. end;
  1032. procedure TZipMaster.SetFilename(Value: string);
  1033. begin
  1034.     FZipFileName := Value;
  1035.     if not (csDesigning in ComponentState) then
  1036.         List;                           { automatically build a new TLIST of contents in "ZipContents" }
  1037. end;
  1038. // NOTE: we will allow a dir to be specified that doesn't exist,
  1039. // since this is not the only way to locate the DLLs.
  1040. procedure TZipMaster.SetDLLDirectory(Value: string);
  1041. var
  1042.     ValLen: Integer;
  1043. begin
  1044.     if Value <> FDLLDirectory then
  1045.     begin
  1046.         ValLen := Length(Value);
  1047.         // if there is a trailing  in dirname, cut it off:
  1048.         if ValLen > 0 then
  1049.             if Value[ValLen] = '' then
  1050.                 SetLength(Value, ValLen - 1); // shorten the dirname by one
  1051.         FDLLDirectory := Value;
  1052.     end;
  1053. end;
  1054. function TZipMaster.GetCount: Integer;
  1055. begin
  1056.     if ZipFileName <> '' then
  1057.         Result := ZipContents.Count
  1058.     else
  1059.         Result := 0;
  1060. end;
  1061. // We do not want that this can be changed, but we do want to see it in the OI.
  1062. procedure TZipMaster.SetVersionInfo(Value: string);
  1063. begin
  1064. end;
  1065. procedure TZipMaster.SetPasswordReqCount(Value: LongWord);
  1066. begin
  1067.     if Value <> FPasswordReqCount then
  1068.     begin
  1069.         if Value > 15 then
  1070.             Value := 15;
  1071.         FPasswordReqCount := Value;
  1072.     end;
  1073. end;
  1074. function TZipMaster.GetZipComment: string;
  1075. begin
  1076.     Result := ConvCodePage(FZipComment, cpdOEM2ISO);
  1077. end;
  1078. procedure TZipMaster.SetZipComment(zComment: string);
  1079. var
  1080.     EOC: ZipEndOfCentral;
  1081.     len: Integer;
  1082.     CommentBuf: pChar;
  1083.     Fatal: Boolean;
  1084. begin
  1085.     FInFileHandle := -1;
  1086.     Fatal := False;
  1087.     CommentBuf := nil;
  1088.     try
  1089.         { ============================ Changed by Jim Turner =========================}
  1090.         if Length(zComment) = 0 then
  1091.             FZipComment := ''
  1092.         else
  1093.             FZipComment := ConvCodePage(zComment, cpdISO2OEM);
  1094.         if Length(ZipFileName) = 0 then
  1095.             raise EZipMaster.CreateResDisp(GE_NoZipSpecified {DS_NoInFile}, True);
  1096.         len := Length(FZipComment);
  1097.         GetMem(CommentBuf, len + 1);
  1098.         StrPLCopy(CommentBuf, zComment, len + 1);
  1099.         FInFileHandle := FileOpen(ZipFileName, fmShareDenyWrite or fmOpenReadWrite);
  1100.         if FInFileHandle <> -1 then     // RP 1.60 -2
  1101.         begin
  1102.             { if FInFileHandle = -1 then
  1103.       raise EZipMaster.CreateResDisp(DS_FileOpen, True);}
  1104.             if FileSeek(FInFileHandle, FZipEOC, 0) = -1 then
  1105.                 raise EZipMaster.CreateResDisp(DS_FailedSeek, True);
  1106.             if (FileRead(FInFileHandle, EOC, SizeOf(EOC)) <> SizeOf(EOC)) or (EOC.HeaderSig <> EndCentralDirSig) then
  1107.                 raise EZipMaster.CreateResDisp(DS_EOCBadRead, True);
  1108.             EOC.ZipCommentLen := len;
  1109.             if FileSeek(FInFileHandle, -SizeOf(EOC), 1) = -1 then
  1110.                 raise EZipMaster.CreateResDisp(DS_FailedSeek, True);
  1111.             Fatal := True;
  1112.             if FileWrite(FInFileHandle, EOC, SizeOf(EOC)) <> SizeOf(EOC) then
  1113.                 raise EZipMaster.CreateResDisp(DS_EOCBadWrite, True);
  1114.             if FileWrite(FInFileHandle, CommentBuf^, len) <> len then
  1115.                 raise EZipMaster.CreateResDisp(DS_NoWrite, True);
  1116.             Fatal := False;
  1117.             // if SetEOF fails we get garbage at the end of the file, not nice but
  1118.                      // also not important.
  1119.             SetEndOfFile(FInFileHandle);
  1120.         end;                            // RP -2
  1121.     except
  1122.         on ews: EZipMaster do
  1123.         begin
  1124.             ShowExceptionError(ews);
  1125.             FZipComment := '';
  1126.         end;
  1127.         on EOutOfMemory do
  1128.         begin
  1129.             ShowZipMessage(GE_NoMem, '');
  1130.             FZipComment := '';
  1131.         end;
  1132.     end;
  1133.     FreeMem(CommentBuf);
  1134.     if FInFileHandle <> -1 then
  1135.         FileClose(FInFileHandle);
  1136.     if Fatal then                       // Try to read the zipfile, maybe it still works.
  1137.         List();
  1138. end;
  1139. { Empty fZipContents and free the storage used for dir entries }
  1140. procedure TZipMaster.FreeZipDirEntryRecords;
  1141. var
  1142.     i: Integer;
  1143. begin
  1144.     if ZipContents.Count = 0 then
  1145.         Exit;
  1146.     for i := (ZipContents.Count - 1) downto 0 do
  1147.     begin
  1148.         if Assigned(ZipContents[i]) then
  1149.         begin
  1150.             StrDispose(pZipDirEntry(ZipContents[i]).ExtraData);
  1151.             // dispose of the memory pointed-to by this entry
  1152.             Dispose(pZipDirEntry(ZipContents[i]));
  1153.         end;
  1154.         ZipContents.Delete(i);          // delete the TList pointer itself
  1155.     end;                                { end for }
  1156.     // The caller will free the FZipContents TList itself, if needed
  1157. end;
  1158. procedure TZipMaster.StartWaitCursor;
  1159. begin
  1160.     if FCurWaitCount = 0 then
  1161.     begin
  1162.         FSaveCursor := Screen.Cursor;
  1163.         Screen.Cursor := crHourglass;
  1164.     end;
  1165.     Inc(FCurWaitCount);
  1166. end;
  1167. procedure TZipMaster.StopWaitCursor;
  1168. begin
  1169.     if FCurWaitCount > 0 then
  1170.     begin
  1171.         Dec(FCurWaitCount);
  1172.         if FCurWaitCount = 0 then
  1173.             Screen.Cursor := FSaveCursor;
  1174.     end;
  1175. end;
  1176. { New in v1.50: We are now looking at the Central zip Dir, instead of
  1177.   the local zip dir.  This change was needed so we could support
  1178.   Disk-Spanning, where the dir for the whole disk set is on the last disk.}
  1179. { The List method reads thru all entries in the central Zip directory.
  1180.   This is triggered by an assignment to the ZipFilename, or by calling
  1181.   this method directly. }
  1182. procedure TZipMaster.List;              { all work is local - no DLL calls }
  1183. var
  1184.     pzd: pZipDirEntry;
  1185.     EOC: ZipEndOfCentral;
  1186.     CEH: ZipCentralHeader;
  1187.     OffsetDiff: Integer;
  1188.     Name: string;
  1189.     i, LiE: Integer;
  1190. begin
  1191.     LiE := 0;
  1192.     if (csDesigning in ComponentState) then
  1193.         Exit;                           { can't do LIST at design time }
  1194.     { zero out any previous entries }
  1195.     FreeZipDirEntryRecords;
  1196.     FRealFileSize := 0;
  1197.     FZipSOC := 0;
  1198.     FSFXOffset := 0;                    // must be before the following "if"
  1199.     FZipComment := '';
  1200.     OffsetDiff := 0;
  1201.     FIsSpanned := False;
  1202.     FDirOnlyCount := 0;
  1203.     if not FileExists(FZipFileName) then
  1204.     begin
  1205.         { let user's program know there's no entries }
  1206.         if Assigned(FOnDirUpdate) then
  1207.             FOnDirUpdate(Self);
  1208.         Exit;                           { don't complain - this may intentionally be a new zip file }
  1209.     end;
  1210.     try
  1211.         StartWaitCursor;
  1212.         try
  1213.             FInFileName := FZipFileName;
  1214.             FDrive := ExtractFileDrive(ExpandFileName(FInFileName)) + '';
  1215.             if not IsDiskPresent then   // Not present, raise an exception!
  1216.                 raise EZipMaster.CreateResDrive(DS_DriveNoMount, FDrive);
  1217.             CheckIfLastDisk(EOC, True); // Not last, w'll get an exception!
  1218.             // The function CheckIfLastDisk read the EOC record, and set some
  1219.             // global values such as FFileSize.  It also opens the zipfile
  1220.    // and left it's open handle in: FInFileHandle
  1221.             FTotalDisks := EOC.ThisDiskNo; // Needed in case GetNewDisk is called.
  1222.             // This could also be set to True if it's the first and only disk.
  1223.             if EOC.ThisDiskNo > 0 then
  1224.                 FIsSpanned := True;
  1225.             // Do we have to request for a previous disk first?
  1226.             if EOC.ThisDiskNo <> EOC.CentralDiskNo then
  1227.             begin
  1228.                 GetNewDisk(EOC.CentralDiskNo);
  1229.                 FFileSize := FileSeek(FInFileHandle, 0, 2); //v1.52i
  1230.                 OffsetDiff := EOC.CentralOffset; //v1.52i
  1231.             end
  1232.             else                        //v1.52i
  1233.                 // Due to the fact that v1.3 and v1.4x programs do not change the archives
  1234.                 // EOC and CEH records in case of a SFX conversion (and back) we have to
  1235.                 // make this extra check.
  1236.                 OffsetDiff := Longword(FFileSize) - EOC.CentralSize - SizeOf(EOC) - EOC.ZipCommentLen;
  1237.             FZipSOC := OffsetDiff;      // save the location of the Start Of Central dir
  1238.             FSFXOffset := FFileSize;    // initialize this - we will reduce it later
  1239.             if FFileSize = 22 then
  1240.                 FSFXOffset := 0;
  1241.             FWrongZipStruct := False;
  1242.             if EOC.CentralOffset <> Longword(OffsetDiff) then
  1243.             begin
  1244.                 FWrongZipStruct := True; // We need this in the ConvertXxx functions.
  1245.                 ShowZipMessage(LI_WrongZipStruct, '');
  1246.             end;
  1247.             // Now we can go to the start of the Central directory.
  1248.             if FileSeek(FInFileHandle, OffsetDiff, 0) = -1 then
  1249.                 raise EZipMaster.CreateResDisp(LI_ReadZipError, True);
  1250.             // Read every entry: The central header and save the information.
  1251.             for i := 0 to (EOC.TotalEntries - 1) do
  1252.             begin
  1253.                 // Read a central header entry for 1 file
  1254.                 while FileRead(FInFileHandle, CEH, SizeOf(CEH)) <> SizeOf(CEH) do //v1.52i
  1255.                 begin
  1256.                     // It's possible that we have the central header split up.
  1257.                     if FDiskNr >= EOC.ThisDiskNo then
  1258.                         raise EZipMaster.CreateResDisp(DS_CEHBadRead, True);
  1259.                     // We need the next disk with central header info.
  1260.                     GetNewDisk(FDiskNr + 1);
  1261.                 end;
  1262.                 //validate the signature of the central header entry
  1263.                 if CEH.HeaderSig <> CentralFileHeaderSig then
  1264.                     raise EZipMaster.CreateResDisp(DS_CEHWrongSig, True);
  1265.                 // Now the filename
  1266.                 SetLength(Name, CEH.FileNameLen);
  1267.                 if FileRead(FInFileHandle, Name[1], CEH.FileNameLen) <> CEH.FileNameLen then
  1268.                     raise EZipMaster.CreateResDisp(DS_CENameLen, True);
  1269.                 // Save version info globally for use by codepage translation routine
  1270.                 FVersionMadeBy0 := CEH.VersionMadeBy0;
  1271.                 FVersionMadeBy1 := CEH.VersionMadeBy1;
  1272.                 Name := ConvCodePage(Name, cpdOEM2ISO);
  1273.                 // Create a new ZipDirEntry pointer.
  1274.                 New(pzd);               // These will be deleted in: FreeZipDirEntryRecords.
  1275.                 // Copy the needed file info from the central header.
  1276.                 CopyMemory(pzd, @CEH.VersionMadeBy0, 42);
  1277.                 pzd^.FileName := ReplaceForwardSlash(Name);
  1278.                 pzd^.Encrypted := (pzd^.Flag and 1) > 0;
  1279.                 // Read the extra data if present new v1.6
  1280.                 if pzd^.ExtraFieldLength > 0 then
  1281.                 begin
  1282.                     pzd^.ExtraData := StrAlloc(CEH.ExtraLen + 1);
  1283.                     if FileRead(FInFileHandle, pzd^.ExtraData[0], CEH.ExtraLen) <> CEH.ExtraLen then // v1.60m
  1284.                         raise EZipMaster.CreateResDisp(LI_ReadZipError, True);
  1285.                 end
  1286.                 else
  1287.                     pzd^.ExtraData := nil;
  1288.                 // Read the FileComment, if present, and save.
  1289.                 if CEH.FileComLen > 0 then
  1290.                 begin
  1291.                     // get the file comment
  1292.                     SetLength(pzd^.FileComment, CEH.FileComLen);
  1293.                     if FileRead(FInFileHandle, pzd^.FileComment[1], CEH.FileComLen) <> CEH.FileComLen then
  1294.                         raise EZipMaster.CreateResDisp(DS_CECommentLen, True);
  1295.                     pzd^.FileComment := ConvCodePage(pzd^.FileComment, cpdOEM2ISO);
  1296.                 end;
  1297.                 if FUseDirOnlyEntries or (ExtractFileName(pzd^.FileName) <> '') then
  1298.                 begin                   // Add it to our contents tabel.
  1299.                     ZipContents.Add(pzd);
  1300.                     // Notify user, when needed, of the next entry in the ZipDir.
  1301.                     if Assigned(FOnNewName) then
  1302.                         FOnNewName(self, i + 1, pzd^);
  1303.                 end
  1304.                 else
  1305.                 begin
  1306.                     Inc(FDirOnlyCount);
  1307.                     StrDispose(pzd^.ExtraData);
  1308.                     Dispose(pzd);
  1309.                 end;
  1310.                 // Calculate the earliest Local Header start
  1311.                 if Longword(FSFXOffset) > CEH.RelOffLocal then
  1312.                     FSFXOffset := CEH.RelOffLocal;
  1313.             end;
  1314.             FTotalDisks := EOC.ThisDiskNo; // We need this when we are going to extract.
  1315.         except
  1316.             on ezl: EZipMaster do       // Catch all Zip List specific errors.
  1317.             begin
  1318.                 ShowExceptionError(ezl);
  1319.                 LiE := 1;
  1320.             end;
  1321.             on EOutOfMemory do
  1322.             begin
  1323.                 ShowZipMessage(GE_NoMem, '');
  1324.                 LiE := 1;
  1325.             end;
  1326.             on E: Exception do
  1327.             begin
  1328.                 // the error message of an unknown error is displayed ...
  1329.                 ShowZipMessage(LI_ErrorUnknown, E.Message);
  1330.                 LiE := 1;
  1331.             end;
  1332.         end;
  1333.     finally
  1334.         StopWaitCursor;
  1335.         if FInFileHandle <> -1 then
  1336.             FileClose(FInFileHandle);
  1337.         if LiE = 1 then
  1338.         begin
  1339.             FZipFileName := '';
  1340.             FSFXOffset := 0;
  1341.         end
  1342.         else
  1343.             FSFXOffset := FSFXOffset + (OffsetDiff - Integer(EOC.CentralOffset)); // Correct the offset for v1.3 and 1.4x
  1344.         // Let the user's program know we just refreshed the zip dir contents.
  1345.         if Assigned(FOnDirUpdate) then
  1346.             FOnDirUpdate(Self);
  1347.     end;
  1348. end;
  1349. // Add a new suffix to the suffix string if contained in the set 'FAddStoreSuffixes'
  1350. procedure TZipMaster.AddSuffix(const SufOption: AddStoreSuffixEnum; var sStr: string; sPos: Integer);
  1351. const
  1352.     SuffixStrings: array[0..17, 0..3] of Char = ('gif', 'png', 'z', 'zip', 'zoo', 'arc', 'lzh', 'arj', 'taz', 'tgz', 'lha', 'rar', 'ace', 'cab', 'gz', 'gzip', 'jar', 'exe');
  1353. begin
  1354.     if SufOption in fAddStoreSuffixes then
  1355.         sStr := sStr + '.' + string(SuffixStrings[sPos]) + ':';
  1356. end;
  1357. procedure TZipMaster.SetZipSwitches(var NameOfZipFile: string; zpVersion: Integer);
  1358. var
  1359.     i: Integer;
  1360.     SufStr, Dts: string;
  1361.     pExFiles: pExcludedFileSpec;
  1362. begin
  1363.     with ZipParms^ do
  1364.     begin
  1365.         if Length(FZipComment) <> 0 then
  1366.         begin
  1367.             fArchComment := StrAlloc(Length(FZipComment) + 1);
  1368.             StrPLCopy(fArchComment, FZipComment, Length(FZipComment) + 1);
  1369.         end;
  1370.         if AddArchiveOnly in fAddOptions then
  1371.             fArchiveFilesOnly := 1;
  1372.         if AddResetArchive in fAddOptions then
  1373.             fResetArchiveBit := 1;
  1374.         if (FFSpecArgsExcl.Count <> 0) then
  1375.         begin
  1376.             fTotExFileSpecs := FFSpecArgsExcl.Count;
  1377.             fExFiles := AllocMem(SizeOf(ExcludedFileSpec) * FFSpecArgsExcl.Count);
  1378.             for i := 0 to (fFSpecArgsExcl.Count - 1) do
  1379.             begin
  1380.                 pExFiles := fExFiles;
  1381.                 Inc(pExFiles, i);
  1382.                 pExFiles.fFileSpec := StrAlloc(Length(fFSpecArgsExcl[i]) + 1);
  1383.                 StrPLCopy(pExFiles.fFileSpec, fFSpecArgsExcl[i], Length(fFSpecArgsExcl[i]) + 1);
  1384.             end;
  1385.         end;
  1386.         // New in v 1.6M Dll 1.6017, used when Add Move is choosen.
  1387.         if FHowToDelete = htdAllowUndo then
  1388.             fHowToMove := True;
  1389.         if FCodePage = cpOEM then
  1390.             fWantedCodePage := 2;
  1391.     end;                                { end with }
  1392.     if (Length(FTempDir) <> 0) then
  1393.     begin
  1394.         ZipParms.fTempPath := StrAlloc(Length(FTempDir) + 1);
  1395.         StrPLCopy(ZipParms.fTempPath, FTempDir, Length(FTempDir) + 1);
  1396.     end;
  1397.     with ZipParms^ do
  1398.     begin
  1399.         Version := zpVersion;           //ZIPVERSION;          // version we expect the DLL to be
  1400.         Caller := Self;                 // point to our VCL instance; returned in callback
  1401.         fQuiet := True;                 { we'll report errors upon notification in our callback }
  1402.         { So, we don't want the DLL to issue error dialogs }
  1403.         ZCallbackFunc := ZCallback;     // pass addr of function to be called from DLL
  1404.         fJunkSFX := False;              { if True, convert input .EXE file to .ZIP }
  1405.         SufStr := '';
  1406.         for i := 0 to Integer(assEXE) do
  1407.             AddSuffix(AddStoreSuffixEnum(i), SufStr, i);
  1408.         if Length(SufStr) <> 0 then
  1409.         begin
  1410.             System.Delete(SufStr, Length(SufStr), 1);
  1411.             pSuffix := StrAlloc(Length(SufStr) + 1);
  1412.             StrPLCopy(pSuffix, SufStr, Length(SufStr) + 1);
  1413.         end;
  1414.         // fComprSpecial := False;     { if True, try to compr already compressed files }
  1415.         fSystem := False;               { if True, include system and hidden files }
  1416.         if AddVolume in fAddOptions then
  1417.             fVolume := True             { if True, include volume label from root dir }
  1418.         else
  1419.             fVolume := False;
  1420.         fExtra := False;                { if True, include extended file attributes-NOT SUPTED }
  1421. fDate := AddFromDate in fAddOptions; { if True, exclude files earlier than specified date }
  1422. { Date := '100592'; }{ Date to include files after; only used if fDate=TRUE }
  1423. dts:=FormatDateTime('mm dd yy',fFromDate);
  1424. for i:=0 to 7 do
  1425. Date[i]:=dts[i+1];   
  1426.         fLevel := FAddCompLevel;        { Compression level (0 - 9, 0=none and 9=best) }
  1427.         fCRLF_LF := False;              { if True, translate text file CRLF to LF (if dest Unix)}
  1428.         fGrow := True;                  { if True, Allow appending to a zip file (-g)}
  1429.         fDeleteEntries := False;        { distinguish bet. Add and Delete }
  1430.         if fTrace then
  1431.             fTraceEnabled := True
  1432.         else
  1433.             fTraceEnabled := False;
  1434.         if fVerbose then
  1435.             fVerboseEnabled := True
  1436.         else
  1437.             fVerboseEnabled := False;
  1438.         if (fTraceEnabled and not fVerbose) then
  1439.             fVerboseEnabled := True;    { if tracing, we want verbose also }
  1440.         if FUnattended then
  1441.             Handle := 0
  1442.         else
  1443.             Handle := fHandle;
  1444.         if AddForceDOS in fAddOptions then
  1445.             fForce := True              { convert all filenames to 8x3 format }
  1446.         else
  1447.             fForce := False;
  1448.         if AddZipTime in fAddOptions then
  1449.             fLatestTime := True         { make zipfile's timestamp same as newest file }
  1450.         else
  1451.             fLatestTime := False;
  1452.         if AddMove in fAddOptions then
  1453.             fMove := True               { dangerous, beware! }
  1454.         else
  1455.             fMove := False;
  1456.         if AddFreshen in fAddOptions then
  1457.             fFreshen := True
  1458.         else
  1459.             fFreshen := False;
  1460.         if AddUpdate in fAddOptions then
  1461.             fUpdate := True
  1462.         else
  1463.             fUpdate := False;
  1464.         if (fFreshen and fUpdate) then
  1465.             fFreshen := False;          { Update has precedence over freshen }
  1466.         if AddEncrypt in fAddOptions then
  1467.             fEncrypt := True            { DLL will prompt for password }
  1468.         else
  1469.             fEncrypt := False;
  1470.         { NOTE: if user wants recursion, then he probably also wants
  1471.           AddDirNames, but we won't demand it. }
  1472.         if AddRecurseDirs in fAddOptions then
  1473.             fRecurse := True
  1474.         else
  1475.             fRecurse := False;
  1476.         if AddHiddenFiles in fAddOptions then
  1477.             fSystem := True
  1478.         else
  1479.             fSystem := False;
  1480.         if AddSeparateDirs in fAddOptions then
  1481.             fNoDirEntries := False { do make separate dirname entries - and also
  1482.             include dirnames with filenames }
  1483.         else
  1484.             fNoDirEntries := True; { normal zip file - dirnames only stored
  1485.         with filenames }
  1486.         if AddDirNames in fAddOptions then
  1487.             fJunkDir := False           { we want dirnames with filenames }
  1488.         else
  1489.             fJunkDir := True;           { don't store dirnames with filenames }
  1490.         pZipFN := StrAlloc(Length(NameOfZipFile) + 1); { allocate room for null terminated string }
  1491.         StrPLCopy(pZipFN, NameOfZipFile, Length(NameOfZipFile) + 1); { name of zip file }
  1492.         if Length(FPassword) > 0 then
  1493.         begin
  1494.             pZipPassword := StrAlloc(Length(FPassword) + 1); { allocate room for null terminated string }
  1495.             StrPLCopy(pZipPassword, FPassword, PWLEN + 1); { password for encryption/decryption }
  1496.         end;
  1497.     end;                                {end else with do }
  1498. end;
  1499. procedure TZipMaster.SetDeleteSwitches; { override "add" behavior assumed by SetZipSwitches: }
  1500. begin
  1501.     with ZipParms^ do
  1502.     begin
  1503.         fDeleteEntries := True;
  1504.         fGrow := False;
  1505.         fJunkDir := False;
  1506.         fMove := False;
  1507.         fFreshen := False;
  1508.         fUpdate := False;
  1509.         fRecurse := False;              // bug fix per Angus Johnson
  1510.         fEncrypt := False;              // you don't need the pwd to delete a file
  1511.     end;
  1512. end;
  1513. procedure TZipMaster.SetUnZipSwitches(var NameOfZipFile: string; uzpVersion: Integer);
  1514. begin
  1515.     with UnZipParms^ do
  1516.     begin
  1517.         Version := uzpVersion;          //UNZIPVERSION;        // version we expect the DLL to be
  1518.         Caller := Self;                 // point to our VCL instance; returned in callback
  1519.         fQuiet := True;                 { we'll report errors upon notification in our callback }
  1520.         { So, we don't want the DLL to issue error dialogs }
  1521.         ZCallbackFunc := ZCallback;     // pass addr of function to be called from DLL
  1522.         if fTrace then
  1523.             fTraceEnabled := True
  1524.         else
  1525.             fTraceEnabled := False;
  1526.         if fVerbose then
  1527.             fVerboseEnabled := True
  1528.         else
  1529.             fVerboseEnabled := False;
  1530.         if (fTraceEnabled and not fVerboseEnabled) then
  1531.             fVerboseEnabled := True;    { if tracing, we want verbose also }
  1532.         if FUnattended then
  1533.             Handle := 0
  1534.         else
  1535.             Handle := fHandle;          // used for dialogs (like the pwd dialogs)
  1536.         fQuiet := True;                 { no DLL error reporting }
  1537.         fComments := False;             { zipfile comments - not supported }
  1538.         fConvert := False;              { ascii/EBCDIC conversion - not supported }
  1539.         if ExtrDirNames in fExtrOptions then
  1540.             fDirectories := True
  1541.         else
  1542.             fDirectories := False;
  1543.         if ExtrOverWrite in fExtrOptions then
  1544.             fOverwrite := True
  1545.         else
  1546.             fOverwrite := False;
  1547.         if ExtrFreshen in fExtrOptions then
  1548.             fFreshen := True
  1549.         else
  1550.             fFreshen := False;
  1551.         if ExtrUpdate in fExtrOptions then
  1552.             fUpdate := True
  1553.         else
  1554.             fUpdate := False;
  1555.         if fFreshen and fUpdate then
  1556.             fFreshen := False;          { Update has precedence over freshen }
  1557.         if ExtrTest in fExtrOptions then
  1558.             fTest := True
  1559.         else
  1560.             fTest := False;
  1561.         { allocate room for null terminated string }
  1562.         pZipFN := StrAlloc(Length(NameOfZipFile) + 1);
  1563.         StrPLCopy(pZipFN, NameOfZipFile, Length(NameOfZipFile) + 1); { name of zip file }
  1564.         UnZipParms.fPwdReqCount := FPasswordReqCount;
  1565.         // We have to be carefull doing an unattended Extract when a password is needed
  1566.         // for some file in the archive. We set it to an unlikely password, this way
  1567.         // encrypted files won't be extracted.
  1568.   // From verion 1.60 and up the event OnPasswordError is called in this case.
  1569.         pZipPassword := StrAlloc(Length(FPassword) + 1); // Allocate room for null terminated string.
  1570.         StrPLCopy(pZipPassword, FPassword, Length(FPassword) + 1); // Password for encryption/decryption.
  1571.     end;                                { end with }
  1572. end;
  1573. function TZipMaster.GetAddPassword: string;
  1574. var
  1575.     p1, p2: string;
  1576. begin
  1577.     p2 := '';
  1578.     if FUnattended then
  1579.         ShowZipMessage(PW_UnatAddPWMiss, '')
  1580.     else
  1581.     begin
  1582.         if (GetPassword(LoadZipStr(PW_Caption, RESOURCE_ERROR), LoadStr(PW_MessageEnter), [pwbCancel], p1) = pwbOk) and (p1 <> '') then
  1583.         begin
  1584.             if (GetPassword(LoadZipStr(PW_Caption, RESOURCE_ERROR), LoadStr(PW_MessageConfirm), [pwbCancel], p2) = pwbOk) and (p2 <> '') then
  1585.             begin
  1586.                 if AnsiCompareStr(p1, p2) <> 0 then
  1587.                 begin
  1588.                     ShowZipMessage(GE_WrongPassword, '');
  1589.                     p2 := '';
  1590.                 end
  1591.                 else
  1592.                     if GAssignPassword then
  1593.                         FPassword := p2;
  1594.             end;
  1595.         end;
  1596.     end;
  1597.     Result := p2;
  1598. end;
  1599. // Same as GetAddPassword, but does NOT verify
  1600. function TZipMaster.GetExtrPassword: string;
  1601. var
  1602.     p1: string;
  1603. begin
  1604.     p1 := '';
  1605.     if FUnattended then
  1606.         ShowZipMessage(PW_UnatExtPWMiss, '')
  1607.     else
  1608.         if (GetPassword(LoadZipStr(PW_Caption, RESOURCE_ERROR), LoadStr(PW_MessageEnter), [pwbCancel, pwbCancelAll], p1) = pwbOk) and (p1 <> '') then
  1609.             if GAssignPassword then
  1610.                 FPassword := p1;
  1611.     Result := p1;
  1612. end;
  1613. function TZipMaster.GetPassword(DialogCaption, MsgTxt: string; pwb: TPasswordButtons; var ResultStr: string): TPasswordButton;
  1614. var
  1615.     Pdlg: TPasswordDlg;
  1616. begin
  1617.     Pdlg := TPasswordDlg.CreateNew2(Self, pwb);
  1618.     ResultStr := Pdlg.ShowModalPwdDlg(DialogCaption, MsgTxt);
  1619.     GModalResult := Pdlg.ModalResult;
  1620.     Pdlg.Free;
  1621.     case GModalResult of
  1622.         mrOk: Result := pwbOk;
  1623.         mrCancel: Result := pwbCancel;
  1624.         mrNoToAll: Result := pwbCancelAll;
  1625.     else
  1626.         Result := pwbAbort;
  1627.     end;
  1628. end;
  1629. procedure TZipMaster.Add;
  1630. begin
  1631.     ExtAdd(0, 0, 0, nil);
  1632. end;
  1633. //---------------------------------------------------------------------------
  1634. // FileAttr are set to 0 as default.
  1635. // FileAttr can be one or a logical combination of the following types:
  1636. // FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_READONLY, FILE_ATTRIBUTE_SYSTEM.
  1637. // FileName is as default an empty string.
  1638. // FileDate is default the system date.
  1639. // EWE: I think 'Filename' is the name you want to use in the zip file to
  1640. // store the contents of the stream under.
  1641. procedure TZipMaster.AddStreamToFile(Filename: string; FileDate, FileAttr: DWORD);
  1642. var
  1643.     st: TSystemTime;
  1644.     ft: TFileTime;
  1645.     FatDate, FatTime: Word;
  1646. begin
  1647.     TraceMessage('AddStreamToFile, fname=' + Filename); //  qqq
  1648.     if Length(Filename) > 0 then
  1649.     begin
  1650.         FFSpecArgs.Clear();
  1651.         FFSpecArgs.Append(FileName);
  1652.     end;
  1653.     if FileDate = 0 then
  1654.     begin
  1655.         GetLocalTime(st);
  1656.         SystemTimeToFileTime(st, ft);
  1657.         FileTimeToDosDateTime(ft, FatDate, FatTime);
  1658.         FileDate := (DWORD(FatDate) shl 16) + FatTime;
  1659.     end;
  1660.     // Check if wildcards are set.
  1661.     if FFSpecArgs.Count > 0 then
  1662.     begin
  1663.         if (AnsiPos(FFSpecArgs.Strings[0], '*') > 0) or (AnsiPos(FFSpecArgs.Strings[0], '?') > 0) then
  1664.             ShowZipMessage(AD_InvalidName, '')
  1665.         else
  1666.             ExtAdd(1, FileDate, FileAttr, nil);
  1667.     end
  1668.     else
  1669.         ShowZipMessage(AD_NothingToZip, '');
  1670. end;
  1671. //---------------------------------------------------------------------------
  1672. function TZipMaster.AddStreamToStream(InStream: TMemoryStream): TZipStream;
  1673. begin
  1674.     if InStream = FZipStream then
  1675.     begin
  1676.         ShowZipMessage(AD_InIsOutStream, '');
  1677.         Result := nil;
  1678.         Exit;
  1679.     end;
  1680.     if InStream.Size > 0 then
  1681.     begin
  1682.         FZipStream.SetSize(InStream.Size + 6);
  1683.         // Call the extended Add procedure:
  1684.         ExtAdd(2, 0, 0, InStream);
  1685.         // The size of the output stream is reset by the dll in ZipParms2 in fOutStreamSize.
  1686.         // Also the size is 6 bytes more than the actual output size because:
  1687.         // - the first two bytes are used as flag, STORED=0 or DEFLATED=8.
  1688.         // - the next four bytes are set to the calculated CRC value.
  1689.   // The size is reset from Inputsize +6 to the actual data size +6.
  1690.         // (you do not have to set the size yourself, in fact it won't be taken into account.
  1691.         // The start of the stream is set to the actual data start.
  1692.         if FSuccessCnt = 1 then
  1693.             FZipStream.Position := 6
  1694.         else
  1695.             FZipStream.SetSize(0);
  1696.     end
  1697.     else
  1698.         ShowZipMessage(AD_NothingToZip, '');
  1699.     Result := FZipStream;
  1700. end;
  1701. //---------------------------------------------------------------------------
  1702. // UseStream = 0 ==> Add file to zip archive file.
  1703. // UseStream = 1 ==> Add stream to zip archive file.
  1704. // UseStream = 2 ==> Add stream to another (zipped) stream.
  1705. procedure TZipMaster.ExtAdd(UseStream: Integer; StrFileDate, StrFileAttr: DWORD; MemStream: TMemoryStream);
  1706. var
  1707.     i, DLLVers: Integer;
  1708.     {$IFNDEF NO_SPAN}
  1709.     drt: Integer;
  1710.     {$ENDIF}
  1711.     {$IFNDEF NO_SFX}
  1712.     SFXResult: Integer;
  1713.     {$ENDIF}
  1714.     AutoLoad: Boolean;
  1715.     TmpZipName: string;
  1716.     pFDS: pFileData;
  1717.     pExFiles: pExcludedFileSpec;
  1718.     len, b, p, RootLen: Integer;
  1719.     rdir: string;
  1720. begin
  1721.     FSuccessCnt := 0;
  1722.     if (UseStream = 0) and (fFSpecArgs.Count = 0) then
  1723.     begin
  1724.         ShowZipMessage(AD_NothingToZip, '');
  1725.         Exit;
  1726.     end;
  1727.     {$IFDEF NO_SPAN}
  1728.     if (AddDiskSpanErase in FAddOptions) or (AddDiskSpan in FAddOptions) then
  1729.     begin
  1730.         ShowZipMessage(DS_NODISKSPAN, '');
  1731.         Exit;
  1732.     end;
  1733.     {$ENDIF}
  1734.     { We must allow a zipfile to be specified that doesn't already exist,
  1735.          so don't check here for existance. }
  1736.     if (UseStream < 2) and (FZipFileName = '') then { make sure we have a zip filename }
  1737.     begin
  1738.         ShowZipMessage(GE_NoZipSpecified, '');
  1739.         Exit;
  1740.     end;
  1741.     // We can not do an Unattended Add if we don't have a password.
  1742.     if FUnattended and (AddEncrypt in FAddOptions) and (FPassword = '') then
  1743.     begin
  1744.         ShowZipMessage(AD_UnattPassword, '');
  1745.         Exit
  1746.     end;
  1747.     // If we are using disk spanning, first create a temporary file
  1748.     if (UseStream < 2) and (AddDiskSpan in FAddOptions) or (AddDiskSpanErase in FAddOptions) then
  1749.     begin
  1750.         {$IFDEF NO_SPAN}
  1751.         ShowZipMessage(DS_NoDiskSpan, '');
  1752.         exit;
  1753.         {$ELSE}
  1754.         // We can't do this type of Add() on a spanned archive.
  1755.         if (AddFreshen in FAddOptions) or (AddUpdate in FAddOptions) then
  1756.         begin
  1757.             ShowZipMessage(AD_NoFreshenUpdate, '');
  1758.             Exit;
  1759.         end;
  1760.         // We can't make a spanned SFX archive
  1761.         if (UpperCase(ExtractFileExt(FZipFileName)) = '.EXE') then
  1762.         begin
  1763.             ShowZipMessage(DS_NoSFXSpan, '');
  1764.             Exit;
  1765.         end;
  1766.         TmpZipName := MakeTempFileName('', '');
  1767.         if FVerbose and Assigned(FOnMessage) then
  1768.             FOnMessage(Self, 0, 'Temporary zipfile: ' + TmpZipName);
  1769.         {$ENDIF}
  1770.     end
  1771.     else
  1772.         TmpZipName := FZipFileName;     // not spanned - create the outfile directly
  1773.     { Make sure we can't get back in here while work is going on }
  1774.     if fZipBusy then
  1775.         Exit;
  1776.     if (UseStream < 2) and (Uppercase(ExtractFileExt(FZipFileName)) = '.EXE')
  1777.         and (FSFXOffset = 0) and not FileExists(FZipFileName) then
  1778.     begin
  1779.         {$IFDEF NO_SFX}
  1780.         ShowZipMessage(SF_NOSFXSUPPORT, '');
  1781.         exit;
  1782.         {$ELSE}
  1783.         try
  1784.             { This is the first "add" operation following creation of a new
  1785.               .EXE archive.  We need to add the SFX code now, before we add
  1786.               the files. }
  1787.             AutoExeViaAdd := True;
  1788.             SFXResult := ConvertSFX;
  1789.             AutoExeViaAdd := False;
  1790.             if SFXResult <> 0 then
  1791.                 raise EZipMaster.CreateResDisk(AD_AutoSFXWrong, SFXResult);
  1792.         except
  1793.             on ews: EZipMaster do       // All SFX creation errors will be caught and returned in this one message.
  1794.             begin
  1795.                 ShowExceptionError(ews);
  1796.                 Exit;
  1797.             end;
  1798.         end;
  1799.         {$ENDIF}
  1800.     end;
  1801.     DLLVers := Load_ZipDll(AutoLoad);
  1802.     if DLLVers = 0 then
  1803.         exit;                           // could not load valid dll
  1804.     fZipBusy := True;
  1805.     Cancel := False;
  1806.     try
  1807.         try
  1808.             ZipParms := AllocMem(SizeOf(ZipParms2));
  1809.             SetZipSwitches(TmpZipName, DLLVers);
  1810.             with ZipParms^ do
  1811.             begin
  1812.                 if UseStream = 1 then
  1813.                 begin
  1814.                     fUseInStream := True;
  1815.                     fInStream := FZipStream.Memory;
  1816.                     fInStreamSize := FZipStream.Size;
  1817.                     fStrFileAttr := StrFileAttr;
  1818.                     fStrFileDate := StrFileDate;
  1819.                 end;
  1820.                 if UseStream = 2 then
  1821.                 begin
  1822.                     fUseOutStream := True;
  1823.                     fOutStream := FZipStream.Memory;
  1824.                     fOutStreamSize := MemStream.Size + 6;
  1825.                     fUseInStream := True;
  1826.                     fInStream := MemStream.Memory;
  1827.                     fInStreamSize := MemStream.Size;
  1828.                 end;
  1829.                 fFDS := AllocMem(SizeOf(FileData) * FFSpecArgs.Count);
  1830.                 for i := 0 to (fFSpecArgs.Count - 1) do
  1831.                 begin
  1832.                     len := Length(FFSpecArgs.Strings[i]);
  1833.                     p := 1;
  1834.                     pFDS := fFDS;
  1835.                     Inc(pFDS, i);
  1836.                     // Added to version 1.60L to support recursion and encryption on a FFileSpec basis.
  1837.                     // Regardless of what AddRecurseDirs is set to, a '>' will force recursion, and a '|' will stop recursion.
  1838.                     pFDS.fRecurse := Word(fRecurse); // Set default
  1839.                     if Copy(FFSpecArgs.Strings[i], 1, 1) = '>' then
  1840.                     begin
  1841.                         pFDS.fRecurse := $FFFF;
  1842.                         Inc(p);
  1843.                     end;
  1844.                     if Copy(FFSpecArgs.Strings[i], 1, 1) = '|' then
  1845.                     begin
  1846.                         pFDS.fRecurse := 0;
  1847.                         Inc(p);
  1848.                     end;
  1849.                     // Also it is possible to specify a password after the FFileSpec, separated by a '<'
  1850.                     // If there is no other text after the '<' then, an existing password, is temporarily canceled.
  1851.                     pFDS.fEncrypt := LongWord(fEncrypt); // Set default
  1852.                     if Length(pZipPassword) > 0 then // v1.60L
  1853.                     begin
  1854.                         pFDS.fPassword := StrAlloc(Length(pZipPassword) + 1);
  1855.                         StrLCopy(pFDS.fPassword, pZipPassword, Length(pZipPassword));
  1856.                     end;
  1857.                     b := AnsiPos('<', FFSpecArgs.Strings[i]);
  1858.                     if b <> 0 then
  1859.                     begin               // Found...
  1860.                         pFDS.fEncrypt := $FFFF; // the new default, but...
  1861.                         StrDispose(pFDS.fPassword);
  1862.                         pFDS.fPassword := nil;
  1863.                         if Copy(FFSpecArgs.Strings[i], b + 1, 1) = '' then
  1864.                             pFDS.fEncrypt := 0 // No password, so cancel for this FFspecArg
  1865.                         else
  1866.                         begin
  1867.                             pFDS.fPassword := StrAlloc(len - b + 1);
  1868.                             StrPLCopy(pFDS.fPassword, Copy(FFSpecArgs.Strings[i], b + 1, len - b), len - b + 1);
  1869.                             len := b - 1;
  1870.                         end;
  1871.                     end;
  1872.                     // And to set the RootDir, possibly later with override per FSpecArg v1.70
  1873.                     if RootDir <> '' then
  1874.                     begin
  1875.                         rdir := ExpandFileName(fRootDir); // allow relative root
  1876.                         RootLen := Length(rdir);
  1877.                         pFDS.fRootDir := StrAlloc(RootLen + 1);
  1878.                         StrPLCopy(pFDS.fRootDir, rdir, RootLen + 1);
  1879.                     end;
  1880.                     pFDS.fFileSpec := StrAlloc(len - p + 2);
  1881.                     StrPLCopy(pFDS.fFileSpec, Copy(FFSpecArgs.Strings[i], p, len - p + 1), len - p + 2);
  1882.                 end;
  1883.                 fSeven := 7;
  1884.             end;                        { end with }
  1885.             ZipParms.argc := fSpecArgs.Count;
  1886.             { pass in a ptr to parms }
  1887.             fSuccessCnt := ZipDLLExec(ZipParms);
  1888.             // If Add was successful and we want spanning, copy the
  1889.             // temporary file to the destination.
  1890.             if (UseStream < 2) and (fSuccessCnt > 0) and
  1891.                 ((AddDiskSpan in FAddOptions) or (AddDiskSpanErase in FAddOptions)) then
  1892.                 {$IFDEF NO_SPAN}
  1893.                 raise EZipMaster.CreateResDisp(DS_NODISKSPAN, true);
  1894.             {$ELSE}
  1895.             begin
  1896.                 // write the temp zipfile to the right target:
  1897.                 if WriteSpan(TmpZipName, FZipFileName) = 0 then
  1898.                 begin                   // Change the zipfilename when needed 1.52N, 1.60N
  1899.                     drt := GetDriveType(pChar(FDrive));
  1900.                     if (drt = DRIVE_FIXED) or (drt = DRIVE_REMOTE) then
  1901.                         FZipFilename := Copy(FZipFileName, 1, Length(FZipFileName) - Length(ExtractFileExt(FZipFileName))) +
  1902.                             Copy(IntToStr(1001 + FDiskNr), 2, 3) + ExtractFileExt(FZipFileName);
  1903.                 end
  1904.                 else
  1905.                     fSuccessCnt := 0;   // error occurred during write span
  1906.                 DeleteFile(TmpZipName);
  1907.             end;
  1908.             {$ENDIF}
  1909.             if (UseStream = 2) and (FSuccessCnt = 1) then
  1910.                 FZipStream.SetSize(ZipParms.fOutStreamSize);
  1911.         except
  1912.             ShowZipMessage(GE_FatalZip, '');
  1913.         end;
  1914.     finally
  1915.         fFSpecArgs.Clear;
  1916.         fFSpecArgsExcl.Clear;
  1917.         with ZipParms^ do
  1918.         begin
  1919.             { Free the memory for the zipfilename and parameters }
  1920.             { we know we had a filename, so we'll dispose it's space }
  1921.             StrDispose(pZipFN);
  1922.             StrDispose(pZipPassword);
  1923.             StrDispose(pSuffix);
  1924.             pZipPassword := nil;        // v1.60L
  1925.             StrDispose(fTempPath);
  1926.             StrDispose(fArchComment);
  1927.             for i := (Argc - 1) downto 0 do
  1928.             begin
  1929.                 pFDS := fFDS;
  1930.                 Inc(pFDS, i);
  1931.                 StrDispose(pFDS.fFileSpec);
  1932.                 StrDispose(pFDS.fPassword); // v1.60L
  1933.                 StrDispose(pFDS.fRootDir); // v1.60L
  1934.             end;
  1935.             FreeMem(fFDS);
  1936.             for i := (fTotExFileSpecs - 1) downto 0 do
  1937.             begin
  1938.                 pExFiles := fExFiles;
  1939.                 Inc(pExFiles, i);
  1940.                 StrDispose(pExFiles.fFileSpec);
  1941.             end;
  1942.             FreeMem(fExFiles);
  1943.         end;
  1944.         FreeMem(ZipParms);
  1945.         ZipParms := nil;
  1946.     end;                                {end try finally }
  1947.     if AutoLoad then
  1948.         Unload_Zip_Dll;
  1949.     Cancel := False;
  1950.     fZipBusy := False;
  1951.     if fSuccessCnt > 0 then
  1952.         List();                         { Update the Zip Directory by calling List method }
  1953. end;
  1954. procedure TZipMaster.Delete;
  1955. var
  1956.     i, DLLVers: Integer;
  1957.     AutoLoad: Boolean;
  1958.     pFDS: pFileData;
  1959.     EOC: ZipEndOfCentral;
  1960.     pExFiles: pExcludedFileSpec;
  1961. begin
  1962.     FSuccessCnt := 0;
  1963.     if fFSpecArgs.Count = 0 then
  1964.     begin
  1965.         ShowZipMessage(DL_NothingToDel, '');
  1966.         Exit;
  1967.     end;
  1968.     if not FileExists(FZipFileName) then
  1969.     begin
  1970.         ShowZipMessage(GE_NoZipSpecified, '');
  1971.         Exit;
  1972.     end;
  1973.     // new 1.7 - stop delete from spanned
  1974.     CheckIfLastDisk(EOC, true);
  1975.     FileClose(fInFileHandle);           // only needed to test it
  1976.     if (IsSpanned) then
  1977.         raise EZipMaster.CreateResDisp(DL_NoDelOnSpan, true);
  1978.     { Make sure we can't get back in here while work is going on }
  1979.     if fZipBusy then
  1980.         Exit;
  1981.     fZipBusy := True;                   { delete uses the ZIPDLL, so it shares the FZipBusy flag }
  1982.     Cancel := False;
  1983.     if ZipDllHandle = 0 then
  1984.     begin
  1985.         AutoLoad := True;               // user's program didn't load the DLL
  1986.         Load_Zip_Dll;                   // load it
  1987.     end
  1988.     else
  1989.         AutoLoad := False;              // user's pgm did load the DLL, so let him unload it
  1990.     if ZipDllHandle = 0 then
  1991.     begin
  1992.         fZipBusy := False;
  1993.         Exit;                           // load failed - error msg was shown to user
  1994.     end;
  1995.     DLLVers := ZipVers;
  1996.     if DLLVers < 170 then
  1997.     begin
  1998.         ShowZipMessage(LZ_OldZipDll, GetZipDllPath(ZipDllHandle));
  1999.         exit;
  2000.     end;
  2001.     try
  2002.         try
  2003.             ZipParms := AllocMem(SizeOf(ZipParms2));
  2004.             SetZipSwitches(fZipFileName, DLLVers);
  2005.             SetDeleteSwitches;
  2006.             with ZipParms^ do
  2007.             begin
  2008.                 fFDS := AllocMem(SizeOf(FileData) * FFSpecArgs.Count);
  2009.                 for i := 0 to (fFSpecArgs.Count - 1) do
  2010.                 begin
  2011.                     pFDS := fFDS;
  2012.                     Inc(pFDS, i);
  2013.                     pFDS.fFileSpec := StrAlloc(Length(fFSpecArgs[i]) + 1);
  2014.                     StrPLCopy(pFDS.fFileSpec, fFSpecArgs[i], Length(fFSpecArgs[i]) + 1);
  2015.                 end;
  2016.                 Argc := fSpecArgs.Count;
  2017.                 fSeven := 7;
  2018.             end;                        { end with }
  2019.             { pass in a ptr to parms }
  2020.             fSuccessCnt := ZipDLLExec(ZipParms);
  2021.         except
  2022.             ShowZipMessage(GE_FatalZip, '');
  2023.         end;
  2024.     finally
  2025.         fFSpecArgs.Clear;
  2026.         fFSpecArgsExcl.Clear;
  2027.         with ZipParms^ do
  2028.         begin
  2029.             StrDispose(pZipFN);
  2030.             StrDispose(pZipPassword);
  2031.             StrDispose(pSuffix);
  2032.             StrDispose(fTempPath);
  2033.             StrDispose(fArchComment);
  2034.             for i := (Argc - 1) downto 0 do
  2035.             begin
  2036.                 pFDS := fFDS;
  2037.                 Inc(pFDS, i);
  2038.                 StrDispose(pFDS.fFileSpec);
  2039.             end;
  2040.             FreeMem(fFDS);
  2041.             for i := (fTotExFileSpecs - 1) downto 0 do
  2042.             begin
  2043.                 pExFiles := fExFiles;
  2044.                 Inc(pExFiles, i);
  2045.                 StrDispose(pExFiles.fFileSpec);
  2046.             end;
  2047.             FreeMem(fExFiles);
  2048.         end;
  2049.         FreeMem(ZipParms);
  2050.         ZipParms := nil;
  2051.     end;
  2052.     if AutoLoad then
  2053.         Unload_Zip_Dll;
  2054.     fZipBusy := False;
  2055.     Cancel := False;
  2056.     if fSuccessCnt > 0 then
  2057.         List;                           { Update the Zip Directory by calling List method }
  2058. end;
  2059. constructor TZipStream.Create;
  2060. begin
  2061.     inherited Create;
  2062.     Clear();
  2063. end;
  2064. destructor TZipStream.Destroy;
  2065. begin
  2066.     inherited Destroy;
  2067. end;
  2068. procedure TZipStream.SetPointer(Ptr: Pointer; Size: Integer);
  2069. begin
  2070.     inherited SetPointer(Ptr, Size);
  2071. end;
  2072. function TZipMaster.ExtractFileToStream(FileName: string): TZipStream;
  2073. begin
  2074.     // Use FileName if set, if not expect the filename in the FFSpecArgs.
  2075.     if FileName <> '' then
  2076.     begin
  2077.         FFSpecArgs.Clear();
  2078.         FFSpecArgs.Add(FileName);
  2079.     end;
  2080.     FZipStream.Clear();
  2081.     ExtExtract(1, nil);
  2082.     if FSuccessCnt <> 1 then
  2083.         Result := nil
  2084.     else
  2085.         Result := FZipStream;
  2086. end;
  2087. function TZipMaster.ExtractStreamToStream(InStream: TMemoryStream; OutSize: Longword): TZipStream;
  2088. begin
  2089.     if InStream = FZipStream then
  2090.     begin
  2091.         ShowZipMessage(AD_InIsOutStream, '');
  2092.         Result := nil;
  2093.         Exit;
  2094.     end;
  2095.     FZipStream.Clear();
  2096.     FZipStream.SetSize(OutSize);
  2097.     ExtExtract(2, InStream);
  2098.     if FSuccessCnt <> 1 then
  2099.         Result := nil
  2100.     else
  2101.         Result := FZipStream;
  2102. end;
  2103. procedure TZipMaster.Extract();
  2104. begin
  2105.     ExtExtract(0, nil);
  2106. end;
  2107. // UseStream = 0 ==> Extract file from zip archive file.
  2108. // UseStream = 1 ==> Extract stream from zip archive file.
  2109. // UseStream = 2 ==> Extract (zipped) stream from another stream.
  2110. procedure TZipMaster.ExtExtract(UseStream: Integer; MemStream: TMemoryStream);
  2111. var
  2112.     i, UnzDLLVers: Integer;
  2113.     OldPRC: Integer;
  2114.     AutoLoad: Boolean;
  2115.     TmpZipName: string;
  2116.     pUFDS: pUnzFileData;
  2117.     {$IFNDEF NO_SPAN}
  2118.     NewName: array[0..512] of Char;
  2119.     {$ENDIF}
  2120. begin
  2121.     FSuccessCnt := 0;
  2122.     OldPRC := FPasswordReqCount;
  2123.     if (UseStream < 2) and (not FileExists(FZipFileName)) then
  2124.     begin
  2125.         ShowZipMessage(GE_NoZipSpecified, '');
  2126.         Exit;
  2127.     end;
  2128.     { Make sure we can't get back in here while work is going on }
  2129.     if fUnzBusy then
  2130.         Exit;
  2131.     // We have to be carefull doing an unattended Extract when a password is needed
  2132.     // for some file in the archive.
  2133.     if FUnattended and (FPassword = '') and not Assigned(FOnPasswordError) then
  2134.     begin
  2135.         FPasswordReqCount := 0;
  2136.         ShowZipMessage(EX_UnAttPassword, '');
  2137.     end;
  2138.     Cancel := False;
  2139.     fUnzBusy := True;
  2140.     // We do a check if we need UnSpanning first, this depends on
  2141.     // The number of the disk the EOC record was found on. ( provided by List() )
  2142.     // If we have a spanned set consisting of only one disk we don't use ReadSpan().
  2143.     if FTotalDisks <> 0 then
  2144.     begin
  2145.         {$IFDEF NO_SPAN}
  2146.         fUnzBusy := False;
  2147.         ShowZipMessage(DS_NODISKSPAN, '');
  2148.         exit;
  2149.         {$ELSE}
  2150.         if FTempDir = '' then
  2151.         begin
  2152.             GetTempPath(MAX_PATH, NewName);
  2153.             TmpZipName := NewName;
  2154.         end
  2155.         else
  2156.             TmpZipName := AppendSlash(FTempDir);
  2157.         if ReadSpan(FZipFileName, TmpZipName) <> 0 then
  2158.         begin
  2159.             fUnzBusy := False;
  2160.             {            if AutoLoad then
  2161.                 Unload_Unz_Dll(); }
  2162.             Exit;
  2163.         end;
  2164.         // We returned without an error, now  TmpZipName contains a real name.
  2165.         {$ENDIF}
  2166.     end
  2167.     else
  2168.         TmpZipName := FZipFileName;
  2169.     UnzDLLVers := Load_UnzDll(AutoLoad);
  2170.     if UnzDllVers = 0 then
  2171.     begin
  2172.         FUnzBusy := false;
  2173.         exit;                           // could not load valid DLL
  2174.     end;
  2175.     //    UnzDLLVers := UnzVers;
  2176.     try
  2177.         try
  2178.             UnZipParms := AllocMem(SizeOf(UnZipParms2));
  2179.             SetUnZipSwitches(TmpZipName, UnzDLLVers);
  2180.             with UnzipParms^ do
  2181.             begin
  2182.                 if ExtrBaseDir <> '' then
  2183.                 begin
  2184.                     fExtractDir := StrAlloc(Length(fExtrBaseDir) + 1);
  2185.                     StrPLCopy(fExtractDir, fExtrBaseDir, Length(fExtrBaseDir));
  2186.                 end
  2187.                 else
  2188.                     fExtractDir := nil;
  2189.                 fUFDS := AllocMem(SizeOf(UnzFileData) * FFSpecArgs.Count);
  2190.                 for i := 0 to (fFSpecArgs.Count - 1) do
  2191.                 begin
  2192.                     pUFDS := fUFDS;
  2193.                     Inc(pUFDS, i);
  2194.                     pUFDS.fFileSpec := StrAlloc(Length(fFSpecArgs[i]) + 1);
  2195.                     StrPLCopy(pUFDS.fFileSpec, fFSpecArgs[i], Length(fFSpecArgs[i]) + 1);
  2196.                 end;
  2197.                 fArgc := FFSpecArgs.Count;
  2198.                 if UseStream = 1 then
  2199.                 begin
  2200.                     for i := 0 to Count - 1 do { Find the wanted file in the ZipDirEntry list. }
  2201.                     begin
  2202.                         with ZipDirEntry(ZipContents[i]^) do
  2203.                         begin
  2204.                             if AnsiStrIComp(pChar(FFSpecArgs.Strings[0]), pChar(FileName)) = 0 then { Found? }
  2205.                             begin
  2206.                                 FZipStream.SetSize(UncompressedSize);
  2207.                                 fUseOutStream := True;
  2208.                                 fOutStream := FZipStream.Memory;
  2209.                                 fOutStreamSize := UncompressedSize;
  2210.                                 fArgc := 1;
  2211.                                 Break;
  2212.                             end;
  2213.                         end;
  2214.                     end;
  2215.                 end;
  2216.                 if UseStream = 2 then
  2217.                 begin
  2218.                     fUseInStream := True;
  2219.                     fInStream := MemStream.Memory;
  2220.                     fInStreamSize := MemStream.Size;
  2221.                     fUseOutStream := True;
  2222.                     fOutStream := FZipStream.Memory;
  2223.                     fOutStreamSize := FZipStream.Size;
  2224.                 end;
  2225.                 fSeven := 7;
  2226.             end;
  2227.             { Argc is now the no. of filespecs we want extracted }
  2228.             if (UseStream = 0) or ((UseStream > 0) and UnZipParms {.up2}.fUseOutStream) then
  2229.                 fSuccessCnt := UnzDLLExec(Pointer(UnZipParms {.up1}));
  2230.             { Remove from memory if stream is not Ok. }
  2231.             if (UseStream > 0) and (FSuccessCnt <> 1) then
  2232.                 FZipStream.Clear();
  2233.             { If UnSpanned we still have this temporary file hanging around. }
  2234.             if FTotalDisks > 0 then
  2235.                 DeleteFile(TmpZipName);
  2236.         except
  2237.             ShowZipMessage(EX_FatalUnZip, '');
  2238.         end;
  2239.     finally
  2240.         fFSpecArgs.Clear;
  2241.         with UnZipParms^ do
  2242.         begin
  2243.             StrDispose(pZipFN);
  2244.             StrDispose(pZipPassword);
  2245.             if (fExtractDir <> nil) then
  2246.                 StrDispose(fExtractDir);
  2247.             for i := (fArgc - 1) downto 0 do
  2248.             begin
  2249.                 pUFDS := fUFDS;
  2250.                 Inc(pUFDS, i);
  2251.                 StrDispose(pUFDS.fFileSpec);
  2252.             end;
  2253.             FreeMem(fUFDS);
  2254.         end;
  2255.         FreeMem(UnZipParms);
  2256.         UnZipParms := nil;
  2257.     end;
  2258.     if FUnattended and (FPassword = '') and not Assigned(FOnPasswordError) then
  2259.         FPasswordReqCount := OldPRC;
  2260.     if AutoLoad then
  2261.         Unload_Unz_Dll;
  2262.     Cancel := False;
  2263.     fUnzBusy := False;
  2264.     { no need to call the List method; contents unchanged }
  2265. end;
  2266. //---------------------------------------------------------------------------
  2267. // Returns 0 if good copy, or a negative error code.
  2268. function TZipMaster.CopyFile(const InFileName, OutFileName: string): Integer;
  2269. const
  2270.     SE_CreateError = -1;                { Error in open or creation of OutFile. }
  2271.     SE_OpenReadError = -3;              { Error in open or Seek of InFile.      }
  2272.     SE_SetDateError = -4;               { Error setting date/time of OutFile.   }
  2273.     SE_GeneralError = -9;
  2274. var
  2275.     InFile, OutFile, InSize, OutSize: Integer;
  2276. begin
  2277.     InSize := -1;
  2278.     OutSize := -1;
  2279.     Result := SE_OpenReadError;
  2280.     FShowProgress := False;
  2281.     if not FileExists(InFileName) then
  2282.         Exit;
  2283.     StartWaitCursor;
  2284.     InFile := FileOpen(InFileName, fmOpenRead or fmShareDenyWrite);
  2285.     if InFile <> -1 then
  2286.     begin
  2287.         if FileExists(OutFileName) then
  2288.             EraseFile(OutFileName, FHowToDelete);
  2289.         OutFile := FileCreate(OutFileName);
  2290.         if OutFile <> -1 then
  2291.         begin
  2292.             Result := CopyBuffer(InFile, OutFile, -1);
  2293.             if (Result = 0) and (FileSetDate(OutFile, FileGetDate(InFile)) <> 0) then
  2294.                 Result := SE_SetDateError;
  2295.             OutSize := FileSeek(OutFile, 0, 2);
  2296.             FileClose(OutFile);
  2297.         end
  2298.         else
  2299.             Result := SE_CreateError;
  2300.         InSize := FileSeek(InFile, 0, 2);
  2301.         FileClose(InFile);
  2302.     end;
  2303.     // An extra check if the filesizes are the same.
  2304.     if (Result = 0) and ((InSize = -1) or (OutSize = -1) or (InSize <> OutSize)) then
  2305.         Result := SE_GeneralError;
  2306.     // Don't leave a corrupted outfile lying around. (SetDateError is not fatal!)
  2307.     if (Result <> 0) and (Result <> SE_SetDateError) then
  2308.         DeleteFile(OutFileName);
  2309.     StopWaitCursor;
  2310. end;
  2311. { Delete a file and put it in the recyclebin on demand. }
  2312. function TZipMaster.EraseFile(const Fname: string; How: DeleteOpts): Integer;
  2313. var
  2314.     SHF: TSHFileOpStruct;
  2315.     DelFileName: string;
  2316. begin
  2317.     // If we do not have a full path then FOF_ALLOWUNDO does not work!?
  2318.     DelFileName := Fname;
  2319.     if ExtractFilePath(Fname) = '' then
  2320.         DelFileName := GetCurrentDir() + '' + Fname;
  2321.     Result := -1;
  2322.     // We need to be able to 'Delete' without getting an error
  2323.     // if the file does not exists as in ReadSpan() can occur.
  2324.     if not FileExists(DelFileName) then
  2325.         Exit;
  2326.     with SHF do
  2327.     begin
  2328.         Wnd := Application.Handle;
  2329.         wFunc := FO_DELETE;
  2330.         pFrom := pChar(DelFileName + #0);
  2331.         pTo := nil;
  2332.         fFlags := FOF_SILENT or FOF_NOCONFIRMATION;
  2333.         if How = htdAllowUndo then
  2334.             fFlags := fFlags or FOF_ALLOWUNDO;
  2335.     end;
  2336.     Result := SHFileOperation(SHF);
  2337. end;
  2338. // Make a temporary filename like: C:...zipxxxx.zip
  2339. // Prefix and extension are default: 'zip' and '.zip'
  2340. function TZipMaster.MakeTempFileName(Prefix, Extension: string): string;
  2341. var
  2342.     Buffer: pChar;
  2343.     len: DWORD;
  2344. begin
  2345.     Buffer := nil;
  2346.     if Prefix = '' then
  2347.         Prefix := 'zip';
  2348.     if Extension = '' then
  2349.         Extension := '.zip';
  2350.     try
  2351.         if Length(FTempDir) = 0 then    // Get the system temp dir
  2352.         begin
  2353.             // 1. The path specified by the TMP environment variable.
  2354.             // 2. The path specified by the TEMP environment variable, if TMP is not defined.
  2355.             // 3. The current directory, if both TMP and TEMP are not defined.
  2356.             len := GetTempPath(0, Buffer);
  2357.             GetMem(Buffer, len + 12);
  2358.             GetTempPath(len, Buffer);
  2359.         end
  2360.         else                            // Use Temp dir provided by ZipMaster
  2361.         begin
  2362.             FTempDir := AppendSlash(FTempDir);
  2363.             GetMem(Buffer, Length(FTempDir) + 13);
  2364.             StrPLCopy(Buffer, FTempDir, Length(FTempDir) + 1);
  2365.         end;
  2366.         if GetTempFileName(Buffer, pChar(Prefix), 0, Buffer) <> 0 then
  2367.         begin
  2368.             DeleteFile(Buffer);         // Needed because GetTempFileName creates the file also.
  2369.             Result := ChangeFileExt(Buffer, Extension); // And finally change the extension.
  2370.         end;
  2371.     finally
  2372.         FreeMem(Buffer);
  2373.     end;
  2374. end;
  2375. function TZipMaster.CopyBuffer(InFile, OutFile, ReadLen: Integer): Integer;
  2376. const
  2377.     SE_CopyError = -2;                  // Write error or no memory during copy.
  2378. var
  2379.     SizeR, ToRead: Integer;
  2380.     Buffer: pBuffer;
  2381. begin
  2382.     // both files are already open
  2383.     Result := 0;
  2384.     ToRead := BufSize;
  2385.     Buffer := nil;
  2386.     try
  2387.         New(Buffer);
  2388.         repeat
  2389.             if ReadLen >= 0 then
  2390.             begin
  2391.                 ToRead := ReadLen;
  2392.                 if BufSize < ReadLen then
  2393.                     ToRead := BufSize;
  2394.             end;
  2395.             SizeR := FileRead(InFile, Buffer^, ToRead);
  2396.             if FileWrite(OutFile, Buffer^, SizeR) <> SizeR then
  2397.             begin
  2398.                 Result := SE_CopyError;
  2399.                 Break;
  2400.             end;
  2401.             if Assigned(FOnProgress) and FShowProgress then
  2402.                 FOnProgress(Self, ProgressUpdate, '', SizeR);
  2403.             if ReadLen > 0 then
  2404.                 Dec(ReadLen, SizeR);
  2405.             Application.ProcessMessages; // Mostly for winsock.
  2406.         until ((ReadLen = 0) or (SizeR <> ToRead));
  2407.     except
  2408.         Result := SE_CopyError;
  2409.     end;
  2410.     if Buffer <> nil then
  2411.         Dispose(Buffer);
  2412.     // leave both files open
  2413. end;
  2414. //---------------------------------------------------------------------------
  2415. // Function to find the EOC record at the end of the archive (on the last disk.)
  2416. // We can get a return value( true::Found, false::Not Found ) or an exception if not found.
  2417. function TZipMaster.CheckIfLastDisk(var EOC: ZipEndOfCentral; DoExcept: boolean): boolean;
  2418. var
  2419.     Sig: Cardinal;
  2420.     DiskNo, Size, i, j: Integer;
  2421.     ShowGarbageMsg: Boolean;
  2422.     First: Boolean;
  2423.     ZipBuf: pChar;
  2424. begin
  2425.     FZipComment := '';
  2426.     First := False;
  2427.     DiskNo := 0;
  2428.     ZipBuf := nil;
  2429.     FZipEOC := 0;
  2430.     // Open the input archive, presumably the last disk.
  2431.     FInFileHandle := FileOpen(FInFileName, fmShareDenyWrite or fmOpenRead);
  2432.     if FInFileHandle = -1 then
  2433.     begin
  2434.         if DoExcept = True then
  2435.             raise EZipMaster.CreateResDisp(DS_NoInFile, True);
  2436.         ShowZipMessage(DS_FileOpen, '');
  2437.         Result := False;
  2438.         Exit;
  2439.     end;
  2440.     // Get the volume number if it's disk from a set.
  2441.     if Pos('PKBACK# ', FVolumeName) = 1 then
  2442.         DiskNo := StrToIntDef(Copy(FVolumeName, 9, 3), 0);
  2443.     // First a check for the first disk of a spanned archive,
  2444.     // could also be the last so we don't issue a warning yet.
  2445.     if (FileRead(FInFileHandle, Sig, 4) = 4) and (Sig = ExtLocalSig) and
  2446.         (FileRead(FInFileHandle, Sig, 4) = 4) and (Sig = LocalFileHeaderSig) then
  2447.     begin
  2448.         First := True;
  2449.         FIsSpanned := True;
  2450.     end;
  2451.     // Next we do a check at the end of the file to speed things up if
  2452.     // there isn't a Zip archive comment.
  2453.     FFileSize := FileSeek(FInFileHandle, -SizeOf(EOC), 2);
  2454.     if FFileSize <> -1 then
  2455.     begin
  2456.         Inc(FFileSize, SizeOf(EOC));    // Save the archive size as a side effect.
  2457.         FRealFileSize := FFileSize;     // There could follow a correction on FFileSize.
  2458.         if (FileRead(FInFileHandle, EOC, SizeOf(EOC)) = SizeOf(EOC)) and
  2459.             (EOC.HeaderSig = EndCentralDirSig) then
  2460.         begin
  2461.             FZipEOC := FFileSize - SizeOf(EOC);
  2462.             Result := True;
  2463.             Exit;
  2464.         end;
  2465.     end;
  2466.     // Now we try to find the EOC record within the last 65535 + sizeof( EOC ) bytes
  2467.     // of this file because we don't know the Zip archive comment length at this time.
  2468.     try
  2469.         Size := 65535 + SizeOf(EOC);
  2470.         if FFileSize < Size then
  2471.             Size := FFileSize;
  2472.         GetMem(ZipBuf, Size + 1);
  2473.         if FileSeek(FInFileHandle, -Size, 2) = -1 then
  2474.             raise EZipMaster.CreateResDisp(DS_FailedSeek, True);
  2475.         if not (FileRead(FInFileHandle, ZipBuf^, Size) = Size) then
  2476.             raise EZipMaster.CreateResDisp(DS_EOCBadRead, True);
  2477.         for i := Size - SizeOf(EOC) - 1 downto 0 do
  2478.             if (ZipBuf[i] = 'P') and (ZipBuf[i + 1] = 'K') and (ZipBuf[i + 2] = #$05) and (ZipBuf[i + 3] = #$06) then
  2479.             begin
  2480.                 FZipEOC := FFileSize - Size + i;
  2481.                 Move(ZipBuf[i], EOC, SizeOf(EOC)); // Copy from our buffer to the EOC record.
  2482.                 // Check if we really are at the end of the file, if not correct the filesize
  2483.     // and give a warning. (It should be an error but we are nice.)
  2484.                 if not (i + SizeOf(EOC) + EOC.ZipCommentLen - Size = 0) then
  2485.                 begin
  2486.                     Inc(FFileSize, i + SizeOf(EOC) + Integer(EOC.ZipCommentLen) - Size);
  2487.                     // Now we need a check for WinZip Self Extractor which makes SFX files which
  2488.                     // allmost always have garbage at the end (Zero filled at 512 byte boundary!)
  2489.                     // In this special case 'we' don't give a warning.
  2490.                     ShowGarbageMsg := True;
  2491.                     if (FRealFileSize - Cardinal(FFileSize) < 512) and ((FRealFileSize mod 512) = 0) then
  2492.                     begin
  2493.                         j := i + SizeOf(EOC) + EOC.ZipCommentLen;
  2494.                         while (ZipBuf[j] = #0) and (j <= Size) do
  2495.                             Inc(j);
  2496.                         if j = Size + 1 then
  2497.                             ShowGarbageMsg := False;
  2498.                     end;
  2499.                     if ShowGarbageMsg then
  2500.                         ShowZipMessage(LI_GarbageAtEOF, '');
  2501.                 end;
  2502.                 // If we have ZipComment: Save it, must be after Garbage check because a #0 is set!
  2503.                 if not (EOC.ZipCommentLen = 0) then
  2504.                 begin
  2505.                     ZipBuf[i + SizeOf(EOC) + EOC.ZipCommentLen] := #0;
  2506.                     FZipComment := ZipBuf + i + SizeOf(EOC); // No codepage translation yet, wait for CEH read.
  2507.                 end;
  2508.                 FreeMem(ZipBuf);
  2509.                 Result := True;
  2510.                 Exit;
  2511.             end;
  2512.         FreeMem(ZipBuf);
  2513.     except
  2514.         FreeMem(ZipBuf);
  2515.         if DoExcept = True then
  2516.             raise;
  2517.     end;
  2518.     if DoExcept = True then
  2519.     begin
  2520.         if (First = False) and (DiskNo <> 0) then
  2521.             raise EZipMaster.CreateResDisk(DS_NotLastInSet, DiskNo);
  2522.         if First = True then
  2523.             if DiskNo = 1 then
  2524.                 raise EZipMaster.CreateResDisp(DS_FirstInSet, True)
  2525.             else
  2526.                 raise EZipMaster.CreateResDisp(DS_FirstFileOnHD, True)
  2527.         else
  2528.             raise EZipMaster.CreateResDisp(DS_NoValidZip, True);
  2529.     end;
  2530.     Result := False;
  2531. end;
  2532. // concat path
  2533. function PathConcat(path, extra: string): string;
  2534. var
  2535.     pathLst: char; pathLen: integer;
  2536. begin
  2537.     pathLen := Length(path);
  2538.     Result := path;
  2539.     if pathLen > 0 then
  2540.     begin
  2541.         pathLst := path[pathLen];
  2542.         if (pathLst <> ':') and (Length(extra) > 0) then
  2543.         begin
  2544.             if (extra[1] = '') = (pathLst = '') then
  2545.             begin
  2546.                 if pathLst = '' then
  2547.                     Result := Copy(path, 1, pathLen - 1) // remove trailing
  2548.                 else
  2549.                     Result := path + ''; // append trailing
  2550.             end;
  2551.         end;
  2552.     end;
  2553.     Result := Result + extra;
  2554. end;
  2555. // returns version - checks valid
  2556. function TZipMaster.Load_ZipDll(var autoload: boolean): integer; // New 1.70
  2557. begin
  2558.     autoload := false;
  2559.     if ZipDllHandle = 0 then
  2560.     begin
  2561.         Result := Load_Zip_Dll;
  2562.         autoload := Result <> 0;
  2563.     end
  2564.     else
  2565.         Result := GetZipDllVersion;
  2566.     if Result < MinZipDllVers then
  2567.     begin
  2568.         ShowZipMessage(LZ_OldZipDll, GetZipDllPath(ZipDllHandle));
  2569.         Unload_Zip_Dll;
  2570.         Result := 0;
  2571.         autoload := false;