Subversion Repositories autosfx

Compare Revisions

No changes between revisions

Regard whitespace Rev HEAD → Rev 1

/Extractor.exe.manifest
File deleted
/Extractor.rc
File deleted
/BrowseFolder.pas
File deleted
/TODO.TXT
File deleted
/LICENSE
File deleted
/MakeSFX.rc
File deleted
/MakeSFX.exe.manifest
File deleted
/resource.h
File deleted
/Readme.md
File deleted
\ No newline at end of file
/MakeSFX.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/BuildTests.bat
1,5 → 1,4
@echo off
MakeSFX Tests\helloworld.zip
MakeSFX Tests\single_file.zip
MakeSFX Tests\test.zip
MakeSFX helloworld.zip
MakeSFX test.zip
pause.
/Future.txt
10,7 → 10,3
testen, was bei leerer zip passieren würde
 
type TZMReplaceOpts = (rplConfirm, rplAlways, rplNewer, rplNever);
 
Bei MakeSFX.exe vorher einen Extraktionstest durchführen? (um z.B. Compressionsfehler etc. auszuschließen?)
 
Einen ZIP-Packer/Modifier, der auch korrekte Kommentare erstellt (Checkboxes zur Unterstützung) machen?
/ExtractorError.dfm
1,9 → 1,11
object ErrorForm: TErrorForm
Left = 222
Top = 133
BorderIcons = [biSystemMenu]
BorderStyle = bsSingle
Caption = 'Fehler'
ClientHeight = 406
ClientWidth = 583
ClientHeight = 365
ClientWidth = 355
Color = clBtnFace
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
12,7 → 14,6
Font.Style = []
OldCreateOrder = False
Position = poMainFormCenter
OnResize = FormResize
PixelsPerInch = 96
TextHeight = 13
object ErrorImg: TImage
814,20 → 815,4
ParentFont = False
TabOrder = 1
end
object SaveBtn: TButton
Left = 64
Top = 328
Width = 97
Height = 25
Caption = 'Liste speichern'
TabOrder = 2
OnClick = SaveBtnClick
end
object SaveDialog: TSaveDialog
DefaultExt = '.txt'
Filter = 'Textdateien (*.txt)|*.txt|Alle Dateien (*.*)|*.*'
Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofEnableSizing]
Left = 320
Top = 8
end
end
/Icon.ico
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/SFXBehavior.pas
41,7 → 41,7
C_ASFX_ET_DES = 'AutoSFX Extraction Target: Extract to Desktop';
C_ASFX_ET_ASK = 'AutoSFX Extraction Target: Choose directory';
 
EINRUECK = '> '; // Optional to all C_ASFX
EINRUECK = '> '; // Optional
 
const
CB_DEFAULT = cbAvoid;
109,15 → 109,12
 
function StripBehavior(c: string): string;
 
procedure StripIt(s: string; allowEinrueck: boolean);
procedure StripIt(s: string);
begin
if allowEinrueck then
begin
c := StringReplace(c, EINRUECK + s+#13#10, '', [rfReplaceAll, rfIgnoreCase]);
c := StringReplace(c, EINRUECK + s+#13, '', [rfReplaceAll, rfIgnoreCase]);
c := StringReplace(c, EINRUECK + s+#10, '', [rfReplaceAll, rfIgnoreCase]);
c := StringReplace(c, EINRUECK + s, '', [rfReplaceAll, rfIgnoreCase]);
end;
 
c := StringReplace(c, s+#13#10, '', [rfReplaceAll, rfIgnoreCase]);
c := StringReplace(c, s+#13, '', [rfReplaceAll, rfIgnoreCase]);
126,20 → 123,20
end;
 
begin
StripIt(C_SIGNATURE, false);
StripIt(C_SIGNATURE);
 
StripIt(C_ASFX_CB_AVO, true);
StripIt(C_ASFX_CB_OVR, true);
StripIt(C_ASFX_CB_NEW, true);
StripIt(C_ASFX_CB_ASK, true);
StripIt(C_ASFX_CB_AVO);
StripIt(C_ASFX_CB_OVR);
StripIt(C_ASFX_CB_NEW);
StripIt(C_ASFX_CB_ASK);
 
StripIt(C_ASFX_CP_NON, true);
StripIt(C_ASFX_CP_BEF, true);
StripIt(C_ASFX_CP_AFT, true);
StripIt(C_ASFX_CP_NON);
StripIt(C_ASFX_CP_BEF);
StripIt(C_ASFX_CP_AFT);
 
StripIt(C_ASFX_ET_HER, true);
StripIt(C_ASFX_ET_DES, true);
StripIt(C_ASFX_ET_ASK, true);
StripIt(C_ASFX_ET_HER);
StripIt(C_ASFX_ET_DES);
StripIt(C_ASFX_ET_ASK);
 
result := c;
end;
/ExtractorMain.pas
1,13 → 1,17
unit ExtractorMain;
 
{$DEFINE USE_DZIP_UNPACK} // recommended
{$DEFINE DEBUG_MODE}
 
{$DEFINE USE_DZIP_UNPACK}
 
// TODO: Implement ExtractionTarget switch
 
interface
 
uses
Windows, SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, ShellAPI,
ExtCtrls, ComCtrls, ZipMstr19, ZMMsgStr19, ZMMsg19, ZMDelZip19,
ZMCompat19, SFXBehavior, ShlObj;
ZMCompat19, SFXBehavior;
 
type
TOverwriteDecision = (odUndefined, odOverwriteAll, odOverwriteNothing);
24,8 → 28,6
procedure AutoTimerTimer(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
private
ExtractionInProcess: boolean;
uz: TZipMaster19;
RenamingOldPrefix: string;
RenamingNewPrefix: string;
zb: TZIPBehavior;
33,21 → 35,21
AbortUnzip: boolean;
StopAskingPassword: boolean;
LastTriedPassword: string;
CachedOverwriteDecision: TOverwriteDecision;
OverwriteDecision: TOverwriteDecision;
{$IFNDEF USE_DZIP_UNPACK}
procedure ExtractDllFromResource(ADirectory: string);
{$ENDIF}
procedure ExtractZipHere(AZipfile: string);
procedure EvExtFNChange(Sender: TObject; var FileName: TZMString; const BaseDir: TZMString; var IsChanged: Boolean);
procedure EvProgress(Sender: TObject; details: TZMProgressDetails);
procedure EvTick(Sender: TObject);
procedure EvCheckTerminate(Sender: TObject; var abort: Boolean);
procedure EvConfirmOverwrite(Sender: TObject; const ForFile: TZMString;
procedure ArcExtFNChange(Sender: TObject; var FileName: TZMString; const BaseDir: TZMString; var IsChanged: Boolean);
procedure ArcProzess(Sender: TObject; details: TZMProgressDetails);
procedure ArcTick(Sender: TObject);
procedure ArcCheckTerminate(Sender: TObject; var abort: Boolean);
procedure ConfirmOverwrite(Sender: TObject; const ForFile: TZMString;
IsOlder: Boolean; var DoOverwrite: Boolean; DirIndex: Integer);
procedure EvPasswordEvent(Sender: TObject; IsZipAction: Boolean;
procedure ArcPassword(Sender: TObject; IsZipAction: Boolean;
var NewPassword: String; const ForFile: TZMString; var RepeatCount: Longword;
var Action: TMsgDlgBtn);
procedure EvSkipEvent(Sender: TObject; const ForFile: TZMString;
procedure SkipEvent(Sender: TObject; const ForFile: TZMString;
SkipType: TZMSkipTypes; var ExtError: Integer);
function StripBaseDir(const s: string): string;
end;
58,11 → 60,10
implementation
 
uses
ExtractorPassword, ExtractorError, Functions, SFXAutoRun, ExtractorComment,
BrowseFolder;
ExtractorPassword, ExtractorError, Functions, SFXAutoRun, ExtractorComment;
 
const
EvPasswordTries = 15;
MaxTries = 15;
 
{$R *.dfm}
 
144,33 → 145,23
 
procedure TMainForm.ExtractZipHere(AZipfile: string);
var
uz: TZipMaster19;
l: TStringList;
s: string;
ec: Integer;
ar: TExecuteSFXAutoRunResult;
GeneralBaseDir: string;
ok: boolean;
const
C_Explorer_Open_Param = '"%s"';
C_Explorer_Select_Param = '/n,/select,"%s"';
EXPLORER_EXE = 'explorer';
resourcestring
Lng_Aborted = 'Der laufende Prozess wurde abgebrochen. Das extrahierten Dateien sind somit unvollständig.';
Lng_Zip_Error = 'ZIP-Master Fehler "%s" (%d)';
Lng_AutoRunFailed = 'SFX-AutoRun fehlgeschlagen. Die entpackten Inhalte werden nun angezeigt.';
Lng_Unknown_Error = 'Unbekannter Fehler: Dateien sind nicht aufzufinden!';
Lng_SelectDir = 'Bitte wählen Sie ein Verzeichnis zum Extrahieren aus. Es wird maximal 1 Datei bzw. Ordner erstellt!';
Lng_WriteProtected = 'Das Verzeichnis ist nicht schreibbar! Bitte wählen Sie ein Anderes.';
begin
AZipfile := ExpandUNCFileName(AZipfile);
RenamingOldPrefix := '';
RenamingNewPrefix := '';
 
if Assigned(uz) then uz.Free; // uz ist global, damit AbortDLL aufgerufen werden kann
 
uz := TZipMaster19.Create(nil);
try
ExtractionInProcess := true;
{$IFNDEF USE_DZIP_UNPACK}
uz.DLLDirectory := GetTempDirectory + DelZipDLL_Name;
{$ENDIF}
184,59 → 175,19
uz.ExtrOptions := [ExtrDirNames, ExtrOverWrite, ExtrFreshen, ExtrUpdate,
ExtrForceDirs, ExtrNTFS];
 
uz.OnExtractOverwrite := EvConfirmOverwrite;
uz.OnProgress := EvProgress;
uz.OnTick := EvTick;
uz.OnCheckTerminate := EvCheckTerminate;
uz.OnPasswordError := EvPasswordEvent;
uz.PasswordReqCount := EvPasswordTries;
uz.OnSkipped := EvSkipEvent;
uz.OnSetExtName := EvExtFNChange;
 
// Find out base dirtory
 
GeneralBaseDir := '';
 
if zb.ExtractionTarget = etExtractHere then
if zb.ConflictBehavior <> cbAvoid then
begin
GeneralBaseDir := ExtractFilePath(AZipfile); // Default
 
if not IsDirectoryWritable(GeneralBaseDir) or
IsAtFlobbyDisk(GeneralBaseDir) then
begin
zb.ExtractionTarget := etDesktop;
uz.OnExtractOverwrite := ConfirmOverwrite;
end;
end;
uz.OnProgress := ArcProzess;
uz.OnTick := ArcTick;
uz.OnCheckTerminate := ArcCheckTerminate;
uz.OnPasswordError := ArcPassword;
uz.PasswordReqCount := MaxTries;
// TODO: Mehr events?
uz.OnSkipped := SkipEvent;
uz.OnSetExtName := ArcExtFNChange;
 
if zb.ExtractionTarget = etDesktop then
begin
GeneralBaseDir := GetSpecialFolderPath(CSIDL_DESKTOP);
 
if not IsDirectoryWritable(GeneralBaseDir) or
IsAtFlobbyDisk(GeneralBaseDir) then
begin
zb.ExtractionTarget := etAsk;
end;
end;
 
if zb.ExtractionTarget = etAsk then
begin
repeat
GeneralBaseDir := MySelectDirectory(Lng_SelectDir);
if GeneralBaseDir = '' then Exit;
 
ok := IsDirectoryWritable(GeneralBaseDir);
if not ok then
begin
MessageDlg(Lng_WriteProtected, mtWarning, [mbOk], 0);
end;
until ok;
end;
 
GeneralBaseDir := IncludeTrailingPathDelimiter(GeneralBaseDir);
 
// Semantic scanning of ZIP to determinate the final extraction directory
 
l := TStringList.Create;
try
// Count the root objects (files OR dirs) in the ZIP
251,25 → 202,23
else if l.Count = 1 then
begin
// 1 Object = Extract it right here!
BaseDir := GeneralBaseDir;
s := BaseDir + l.Strings[0];
 
RenamingOldPrefix := l.Strings[0]; // = StripBaseDir(S);
 
s := ExtractFilePath(AZipfile) + l.Strings[0];
BaseDir := ExtractFilePath(AZipfile);
RenamingOldPrefix := StripBaseDir(S);
if zb.ConflictBehavior = cbAvoid then
begin
s := SearchNextFreeName(s, LooksLikeDir(s));
s := SearchNextFreeName(s);
end;
 
RenamingNewPrefix := StripBaseDir(s);
// TODO: helloworld.exe schlägt fehl!
RenamingNewPrefix := StripBaseDir(S); // We need to change the name!
end
else
begin
// 2+ Objects = Extract them in a separate folder
s := GeneralBaseDir + ExtractFileNameWithoutExt(AZipfile) + PathDelim;
s := ChangeFileExt(AZipfile, '');
if zb.ConflictBehavior = cbAvoid then
begin
s := SearchNextFreeName(s, true);
s := SearchNextFreeName(s);
MkDir(s);
end
else
280,7 → 229,7
end;
BaseDir := IncludeTrailingPathDelimiter(BaseDir);
 
uz.ExtrBaseDir := BaseDir;
uz.ExtrBaseDir := BaseDir; // TODO: andere ordner erlauben
 
// Pre-Extract-Dialog
 
309,7 → 258,6
 
if ErrorForm.ErrorsAvailable then
begin
Hide;
ErrorForm.ShowModal;
end;
 
337,9 → 285,8
if DirectoryExists(s) then
begin
// If it is a folder, open it
 
ShellExecute(0, 'open', EXPLORER_EXE,
PChar(Format(C_Explorer_Open_Param, [s])), '', SW_NORMAL);
ShellExecute(0, 'open', 'explorer',
PChar('"'+s+'"'), '', SW_NORMAL);
end
else if FileExists(s) then
begin
349,27 → 296,23
// Im Moment wird bei einem BESTEHENDEN Fenster
// die Selektion nicht durchgeführt.
 
ShellExecute(0, 'open', EXPLORER_EXE,
PChar(Format(C_Explorer_Select_Param, [s])), '', SW_NORMAL);
ShellExecute(0, 'open', 'explorer',
PChar('/n,/select,"'+s+'"'), '', SW_NORMAL);
end
else
begin
if not AbortUnzip then
begin
MessageDlg(Lng_Unknown_Error, mtError, [mbOk], 0);
end;
end;
end;
finally
l.Free;
end;
finally
uz.Free;
ExtractionInProcess := false;
end;
end;
 
procedure TMainForm.EvProgress(Sender: TObject; details: TZMProgressDetails);
procedure TMainForm.ArcProzess(Sender: TObject; details: TZMProgressDetails);
begin
CurrentFileLabel.Caption := details.ItemName;
 
382,26 → 325,27
Application.ProcessMessages;
end;
 
procedure TMainForm.EvExtFNChange(Sender: TObject;
procedure TMainForm.ArcExtFNChange(Sender: TObject;
var FileName: TZMString; const BaseDir: TZMString;
var IsChanged: Boolean);
begin
if RenamingOldPrefix = RenamingNewPrefix then Exit;
if RenamingOldPrefix = RenamingOldPrefix then Exit;
 
FileName := RenamingNewPrefix + Copy(FileName, 1+Length(RenamingOldPrefix), Length(FileName)-Length(RenamingOldPrefix));
IsChanged := true;
end;
 
procedure TMainForm.EvTick(Sender: TObject);
procedure TMainForm.ArcTick(Sender: TObject);
begin
Application.ProcessMessages;
end;
 
procedure TMainForm.EvCheckTerminate(Sender: TObject; var abort: Boolean);
procedure TMainForm.ArcCheckTerminate(Sender: TObject; var abort: Boolean);
begin
abort := AbortUnzip;
end;
 
procedure TMainForm.EvConfirmOverwrite(Sender: TObject; const ForFile: TZMString;
procedure TMainForm.ConfirmOverwrite(Sender: TObject; const ForFile: TZMString;
IsOlder: Boolean; var DoOverwrite: Boolean; DirIndex: Integer);
resourcestring
Lng_Overwrite = 'Bestehende Datei "%s" überschreiben?';
428,31 → 372,27
Exit;
end;
 
if CachedOverwriteDecision = odUndefined then
if OverwriteDecision = odUndefined then
begin
res := MessageDlg(Format(Lng_Overwrite, [ForFile]), mtConfirmation, [mbYes, mbNo, mbYesToAll, mbNoToAll], 0);
DoOverwrite := (res = mrYes) or (res = mrYesToAll);
if res = mrNoToAll then CachedOverwriteDecision := odOverwriteNothing;
if res = mrYesToAll then CachedOverwriteDecision := odOverwriteAll;
if res = mrNoToAll then OverwriteDecision := odOverwriteNothing;
if res = mrYesToAll then OverwriteDecision := odOverwriteAll;
end
else
begin
DoOverwrite := CachedOverwriteDecision = odOverwriteAll;
DoOverwrite := OverwriteDecision = odOverwriteAll;
end;
end
else if zb.ConflictBehavior = cbAvoid then
begin
// Nothing to do
end;
end;
 
procedure TMainForm.EvPasswordEvent(Sender: TObject; IsZipAction: Boolean;
procedure TMainForm.ArcPassword(Sender: TObject; IsZipAction: Boolean;
var NewPassword: String; const ForFile: TZMString; var RepeatCount: Longword;
var Action: TMsgDlgBtn);
var
repc: integer;
begin
repc := EvPasswordTries - RepeatCount + 1;
repc := MaxTries - RepeatCount + 1;
 
// Eine Passworteingabe wurde abgebrochen. Frage nicht mehr nach.
if StopAskingPassword then Exit;
474,7 → 414,7
end;
end;
 
if PasswordDlg.ShowModal(StripBaseDir(ForFile), repc, EvPasswordTries) = mrOk then
if PasswordDlg.ShowModal(StripBaseDir(ForFile), repc, MaxTries) = mrOk then
begin
NewPassword := PasswordDlg.Password.Text;
if NewPassword = '' then NewPassword := ' '; // Neue Eingabe erzwingen.
491,34 → 431,19
resourcestring
Lng_AbortExtract = 'Extrahieren abbrechen?';
begin
if not ExtractionInProcess then
begin
Close;
Exit;
end;
 
if MessageDlg(Lng_AbortExtract, mtConfirmation, mbYesNoCancel, 0) = mrYes then
begin
CancelBtn.Enabled := false;
uz.AbortDLL;
AbortUnzip := true;
// Close wird durch den Timer durchgeführt
Exit;
end;
end;
 
procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if not ExtractionInProcess then
begin
CanClose := true;
Exit;
end;
 
if not AbortUnzip then
begin
CancelBtn.Click;
CanClose := false;
CancelBtn.Click;
end;
end;
 
526,6 → 451,9
resourcestring
Lng_Extracting = 'Extrahiere Dateien. Bitte warten...';
begin
{$IFDEF DEBUG_MODE}
Caption := Caption + ' (Debug)';
{$ENDIF}
WaitLabel.Caption := Lng_Extracting;
WaitLabel.Left := progressBar.Width div 2 - WaitLabel.Width div 2;
CurrentFileLabel.Caption := '';
572,10 → 500,6
{$ENDIF}
 
procedure TMainForm.AutoTimerTimer(Sender: TObject);
resourcestring
Lng_NakedSFX = 'Das selbstentpackende Archiv (SFX) beschädigt oder ungültig. Wenn Sie diese Datei aus dem Internet bezogen haben, laden Sie sie bitte erneut herunter.';
Lng_FileNotFound = 'Die durch Parameter angegebene Datei "%s" kann nicht gefunden werden!';
Lng_TooManyArguments = 'Zu viele Argumente!';
begin
AutoTimer.Enabled := false;
 
584,21 → 508,7
{$ENDIF}
 
try
if IsExtractable(ParamStr(0)) then
begin
ExtractZipHere(ParamStr(0));
end
else
begin
// Der Extractor ist "nackt" oder das SFX beschädigt
 
if ParamCount = 0 then
begin
MessageDlg(Lng_NakedSFX, mtError, [mbOk], 0);
end
else if ParamCount = 1 then
begin
// In diesem Zustand erlauben wir, fremde SFX zu entpacken (auch für Debugging-Zwecke)
{$IFDEF DEBUG_MODE}
if FileExists(ParamStr(1)) then
begin
ExtractZipHere(ParamStr(1));
605,16 → 515,15
end
else
begin
MessageDlg(Lng_FileNotFound, mtError, [mbOk], 0);
{$ENDIF}
 
ExtractZipHere(ParamStr(0));
 
{$IFDEF DEBUG_MODE}
end;
end
else if ParamCount = 2 then
begin
// Future: Mehr als nur 1 Parameter erlauben?
MessageDlg(Lng_TooManyArguments, mtError, [mbOk], 0);
end;
end;
{$ENDIF}
finally
AbortUnzip := true; // Damit es zu keiner Abfrage kommt
Close;
end;
end;
626,7 → 535,7
result := Copy(s, Length(BaseDir)+1, Length(s)-Length(BaseDir));
end;
 
procedure TMainForm.EvSkipEvent(Sender: TObject; const ForFile: TZMString;
procedure TMainForm.SkipEvent(Sender: TObject; const ForFile: TZMString;
SkipType: TZMSkipTypes; var ExtError: Integer);
resourcestring
Lng_PasswordWrong = 'Das Passwort wurde zu oft falsch eingegeben. Die Datei "%s" wird nicht extrahiert.';
636,7 → 545,7
MessageDlg(Format(Lng_PasswordWrong, [ForFile]), mtError, [mbOk], 0);
LastTriedPassword := '';
end;
ErrorForm.NewError(ForFile, SkipType);
ErrorForm.NewError(StripBaseDir(ForFile));
end;
 
end.
/Extractor.res
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/Extractor.cfg
37,7 → 37,6
-O"c:\programme\borland\bds\4.0\lib\Debug;c:\programme\borland\bds\4.0\Lib\Debug\Indy10;zmstr1900102"
-I"c:\programme\borland\bds\4.0\lib\Debug;c:\programme\borland\bds\4.0\Lib\Debug\Indy10;zmstr1900102"
-R"c:\programme\borland\bds\4.0\lib\Debug;c:\programme\borland\bds\4.0\Lib\Debug\Indy10;zmstr1900102"
-w-UNIT_PLATFORM
-w-UNSAFE_TYPE
-w-UNSAFE_CODE
-w-UNSAFE_CAST
/Icons/Software used.txt
File deleted
/Icons/RarSFX.ico
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/Icons/RarSFX Source/RarSFX.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/Icons/RarSFX Source/RarSFX.psd
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/Icons/RarSFX Source/Source.txt
File deleted
/Readme.txt
0,0 → 1,87
VIATHINKSOFT AUTOSFX
====================
 
Benefits
--------
 
* Compatible with WinRAR and other software (Stub is small enough)
* Compatible with Linux' UnZip (No Warnings!)
* Compatible with AuthentiCode
* Compatible with Windows 7
* Compatible with Windows 95
 
Current overhead
----------------
 
458 KB (Delphi 2006)
 
Structure of a ViaThinkSoft AutoSFX Archive
-------------------------------------------
 
1. Extractor [UPX'ed]
includes DelZip190.dll (B4) as Resource
2. ZIP (Offset adjusted)
File comment includes "ViaThinkSoft AutoSFX Archive"
3. Optional: Authenticode Certificate
 
Process
-------
 
1. Extract DelZip DLL into TempDir
2. Extract contents directly
3. Open the extracted data and/or execute special AutoRun.inf (see below)
4. Delete the DLL from TempDir
 
Behavior
--------
 
ZIP has 1 file
=> Extract in the same directory as the SFX
Is it a directory?
=> Open the new directory in Windows Explorer
is it a file?
=> Open Windows Explorer and select the new file.
ZIP has 2+ files
=> Create a directory with the name of the SFX and extract into it
=> Open the new created directory in Windows Explorer
 
Semantic archive comment
------------------------
 
The extractor looks into the file comment to determinate the behavior
while unzipping. YOU can influence the behavior when creating your
ZIP files.
 
Following switches are possible:
 
C_ASFX_CB_OVR = 'AutoSFX Conflict Behavior: Overwrite all';
C_ASFX_CB_NEW = 'AutoSFX Conflict Behavior: Overwrite older';
C_ASFX_CB_ASK = 'AutoSFX Conflict Behavior: Ask';
C_ASFX_CB_AVO = 'AutoSFX Conflict Behavior: Avoid';
 
C_ASFX_CP_BEF = 'AutoSFX Comment Presentation: Before extracting';
C_ASFX_CP_AFT = 'AutoSFX Comment Presentation: After extracting';
C_ASFX_CP_NON = 'AutoSFX Comment Presentation: None';
 
C_ASFX_FC_THS = 'AutoSFX Extraction Target: Extract here';
C_ASFX_FC_DSK = 'AutoSFX Extraction Target: Extract to Desktop';
C_ASFX_FC_ASK = 'AutoSFX Extraction Target: Choose directory';
 
Special AutoRun.inf
-------------------
 
[AutoSFX]
Operation=open ; Part of ShellExecute. Usually 'open' or 'runass' (e.g. for admin privilegies)
FileName=AutoRun.exe ; The filename to be executed
Parameters= ; Optional parameters
Directory= ; Optional Working directory
ShowCmd= ; (See MSDN Reference) Usually WS_NORMAL or WS_HIDE
OpenUnzippedContent=true ; After we have opened the application, should we still show the extracted data in Windows Explorer? (Default behavior if not AutoRun is set)
 
More information about the first 5 values:
http://msdn.microsoft.com/en-us/library/bb762153(VS.85).aspx
 
// It is forbidden that the AutoRun calls its own creator (the SFX again).
 
 
(C) 2010 ViaThinkSoft
/zmstr1900102/Demos/Demo7/ImageStream.identcache
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/zmstr1900102/Demos/Demo7/ImageStream.bdsproj.local
0,0 → 1,2
<?xml version="1.0" encoding="utf-8"?>
<BorlandProject/>
/zmstr1900102/Demos/Demo7/Unit1.dcu
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/MakeSFX.exe
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/MakeSFX.dpr
10,7 → 10,6
Windows,
Classes,
ZipMstr19,
Dialogs,
Functions in 'Functions.pas',
SFXBehavior in 'SFXBehavior.pas';
 
20,12 → 19,14
ZIP_EXE = 'Tools\zip.exe';
RemoveSignature_EXE = 'Tools\RemoveSignature.exe';
 
procedure DoMakeSFX(AFilename: string);
var
Dst: string;
Src, Dst: string;
i: integer;
s1, s2: TFileStream;
x: TZipMaster19;
 
resourcestring
ImportantFileNotFound = 'Error: Important file "%s" not found!';
LngErrorWhileCopy = 'Error: Could not copy "%s" to "%s".';
LngErrorWhileExecuting = 'Error while executing "%s".';
SourceFileNotFound = 'Source file "%s" not found.';
37,20 → 38,46
Lng_ModifyZIPComment = 'Modify ZIP Comment...';
Lng_SignSfx = 'Sign the SFX...';
Lng_Finished = 'Finished! :-)';
Lng_Title = 'ViaThinkSoft AutoSFX';
Lng_Usage1 = 'Usage:';
Lng_Usage2 = 'MakeSFX [File1.zip [File2.zip...]]';
 
{$R *.res}
 
begin
if not FileExists(AFilename) then
WriteLn(Lng_Title);
WriteLn('');
WriteLn(Lng_Usage1);
WriteLn(Lng_Usage2);
WriteLn('');
 
if not FileExists(ExtractFilePath(ParamStr(0)) + Extractor_EXE) then
begin
WriteLn(Format(SourceFileNotFound, [AFilename]));
WriteLn(Format(ImportantFileNotFound, [Extractor_EXE]));
{$IFDEF DELAY_ON_ERROR}
Sleep(2000);
{$ENDIF}
ExitCode := 1;
ExitCode := 2;
Exit;
end;
 
Dst := ChangeFileExt(AFilename, '.exe');
for i := 1 to ParamCount do
begin
Src := ParamStr(i);
 
WriteLn(Format(Lng_In+#9+'%s', [AFilename]));
if not FileExists(Src) then
begin
WriteLn(Format(SourceFileNotFound, [Src]));
{$IFDEF DELAY_ON_ERROR}
Sleep(2000);
{$ENDIF}
ExitCode := 1;
Continue;
end;
 
Dst := ChangeFileExt(Src, '.exe');
 
WriteLn(Format(Lng_In+#9+'%s', [Src]));
WriteLn(Format(Lng_Out+#9+'%s', [Dst]));
WriteLn('');
 
61,7 → 88,7
Sleep(2000);
{$ENDIF}
ExitCode := 1;
Exit;
Continue;
end;
 
// Remove the signature of Extractor first (otherwise signing will fail later)
77,7 → 104,7
Sleep(2000);
{$ENDIF}
ExitCode := 1;
Exit;
Continue;
{$ENDIF}
end;
 
87,7 → 114,7
try
s1.Seek(0, soEnd);
 
s2 := TFileStream.Create(AFilename, fmOpenRead or fmShareDenyWrite);
s2 := TFileStream.Create(Src, fmOpenRead or fmShareDenyWrite);
try
s1.CopyFrom(s2, s2.Size);
finally
107,7 → 134,7
Sleep(2000);
{$ENDIF}
ExitCode := 1;
Exit;
Continue;
end;
 
WriteLn(#9 + Lng_ModifyZIPComment);
150,7 → 177,7
Sleep(2000);
{$ENDIF}
ExitCode := 1;
Exit;
Continue;
{$ENDIF}
end;
 
158,59 → 185,5
WriteLn('');
end;
 
{$R *.res}
 
var
i: integer;
od: TOpenDialog;
resourcestring
Lng_Title = 'ViaThinkSoft AutoSFX';
Lng_Usage1 = 'Usage:';
Lng_Usage2 = 'MakeSFX [File1.zip [File2.zip...]]';
ImportantFileNotFound = 'Error: Important file "%s" not found!';
begin
WriteLn(Lng_Title);
WriteLn('');
WriteLn(Lng_Usage1);
WriteLn(Lng_Usage2);
WriteLn('');
 
if not FileExists(ExtractFilePath(ParamStr(0)) + Extractor_EXE) then
begin
WriteLn(Format(ImportantFileNotFound, [Extractor_EXE]));
{$IFDEF DELAY_ON_ERROR}
Sleep(2000);
{$ENDIF}
ExitCode := 2;
Exit;
end;
 
if ParamCount = 0 then
begin
od := TOpenDialog.Create(nil);
try
od.DefaultExt := '.zip';
od.Filter := 'ZIP-Archiv (*.zip)|*.zip|Alle Dateien (*.*)|*.*';
od.Options := [ofAllowMultiSelect, ofFileMustExist, ofHideReadOnly,
ofPathMustExist, ofEnableSizing];
if od.Execute then
begin
for i := 0 to od.Files.Count - 1 do
begin
DoMakeSFX(od.Files.Strings[i]);
end;
end;
finally
od.Free;
end;
end
else
begin
for i := 1 to ParamCount do
begin
DoMakeSFX(ParamStr(i));
end;
end;
 
// TODO: Es gibt bei Win2000 außerhalb des debuggers eine AV...
end.
/td.txt
0,0 → 1,15
Delphi 6: Projekteinstellungen prüfen. Debugging bei Extractor aus
Versioninfo für alle Projekte
MakeSFX.ico auch in 16x16 (ref: cdfview.dll)
 
BUG:
- W95 issue
- Ungültige Resourcendatei...
 
Sicherheitslücke
- Der AutoRun kann eine unendliche Rekursion der Entpacker starten!
Wie kann man alle Variationen feststellen?
 
???
- Ist es möglich, dass erst Pwd-Dialog und dann Overwrite-Dialog kommt?
=> Overwrite dialog soll nicht kommen bei "StopAskingPassword" + Verschlüsselt
/ExtractorMain.dfm
67,7 → 67,6
Font.Style = []
ParentFont = False
TabOrder = 1
TabStop = False
OnClick = CancelBtnClick
end
object itemBar: TProgressBar
79,6 → 78,7
TabOrder = 2
end
object AutoTimer: TTimer
Interval = 100
OnTimer = AutoTimerTimer
Left = 320
Top = 8
/Functions.pas
3,8 → 3,7
interface
 
uses
Forms, Windows, Classes, SysUtils, ShellAPI,
ZipMstr19, ZmUtils19, ShlObj, ActiveX;
Windows, Classes, SysUtils, ShellAPI;
 
type
TLineBreak = (lbWindows, lbLinux, lbMac);
16,11 → 15,7
function GetTempDirectory: String;
function NormalizeLineBreaks(s: string; mode: TLineBreak): string;
function ExtractFileNameWithoutExt(const fil: string): string;
function SearchNextFreeName(s: string; wantDir: boolean): string;
function GetSpecialFolderPath(const Folder: integer): string;
function IsExtractable(AFilename: string): boolean;
function IsDirectoryWritable(const Dir: String): Boolean;
function IsAtFlobbyDisk(AFileOrDir: string): boolean;
function SearchNextFreeName(s: string): string;
 
implementation
 
155,7 → 150,7
result := Copy(ExtractFileName(fil), 1, Length(ExtractFileName(fil))-Length(ExtractFileExt(fil)));
end;
 
function SearchNextFreeName(s: string; wantDir: boolean): string;
function SearchNextFreeName(s: string): string;
var
i: integer;
begin
162,87 → 157,27
if not FileExists(s) and not DirectoryExists(s) then
begin
result := s;
if wantDir then result := IncludeTrailingPathDelimiter(result);
Exit;
end;
 
i := 2;
 
if wantDir then
if FileExists(s) then
begin
s := ExcludeTrailingPathDelimiter(s);
repeat
result := Format('%s (%d)', [s, i]);
result := Format('%s (%d)%s', [ExtractFileNameWithoutExt(s), i, ExtractFileExt(s)]);
inc(i);
until not DirectoryExists(result) and not FileExists(result);
result := IncludeTrailingPathDelimiter(result);
until not DirectoryExists(result);
end
else
else if DirectoryExists(s) then
begin
s := ExcludeTrailingPathDelimiter(s);
repeat
result := Format('%s (%d)%s', [ExtractFilePath(s)+ExtractFileNameWithoutExt(s), i, ExtractFileExt(s)]);
result := Format('%s (%d)', [s, i]);
inc(i);
until not DirectoryExists(result) and not FileExists(result);
until not DirectoryExists(result); // Todo: Legt man sich hier nun auf einen ordnernamen fest???
result := IncludeTrailingPathDelimiter(result);
end;
end;
 
// GetSpecialFolderPath
// Ref: http://www.wer-weiss-was.de/theme159/article1058561.html
function GetSpecialFolderPath(const Folder: integer): string;
var
PIDL: PItemIDList;
Path: array[0..MAX_PATH] of char;
Malloc: IMalloc;
begin
Path := '';
if Succeeded((SHGetSpecialFolderLocation(0, Folder, PIDL))) then
if (SHGetPathFromIDList(PIDL, Path)) then
if Succeeded(ShGetMalloc(Malloc)) then
begin
Malloc.Free(PIDL);
Malloc := nil;
end;
Result := Path;
end;
 
function IsExtractable(AFilename: string): boolean;
var
q: integer;
uz: TZipMaster19;
begin
// TODO: Ist die Funktion gut? Fraglich, ob EOC64 ein Teil von EOC ist.
uz := TZipMaster19.Create(nil);
try
q := uz.QueryZip(AFilename);
result := true;
if (q and zqbHasLocal) <> zqbHasLocal then result := false;
if (q and zqbHasCentral) <> zqbHasCentral then result := false;
if ((q and zqbHasEOC) <> zqbHasEOC) and
((q and zqbHasEOC64) <> zqbHasEOC64) then result := false;
finally
uz.Free;
end;
end;
 
// Ref: http://www.delphiarea.com/articles/how-to-find-if-a-directory-is-writable/
function IsDirectoryWritable(const Dir: String): Boolean;
var
TempFile: array[0..MAX_PATH] of Char;
begin
if GetTempFileName(PChar(Dir), 'DA', 0, TempFile) <> 0 then
Result := Windows.DeleteFile(TempFile)
else
Result := False;
end;
 
function IsAtFlobbyDisk(AFileOrDir: string): boolean;
var
s: string;
begin
s := ExtractFileDrive(AFileOrDir);
s := UpperCase(s);
 
result := (s = 'A:') or (s = 'B:');
end;
 
end.
/Extractor.exe
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/Extractor.dpr
14,8 → 14,7
ExtractorComment in 'ExtractorComment.pas' {CommentForm},
Functions in 'Functions.pas',
SFXAutoRun in 'SFXAutoRun.pas',
SFXBehavior in 'SFXBehavior.pas',
BrowseFolder in 'BrowseFolder.pas';
SFXBehavior in 'SFXBehavior.pas';
 
{$R *.res}
 
/MakeSFX.bdsproj
130,7 → 130,7
<Directories Name="UsePackages">False</Directories>
</Directories>
<Parameters>
<Parameters Name="RunParams"></Parameters>
<Parameters Name="RunParams">helloworld.zip</Parameters>
<Parameters Name="HostApplication"></Parameters>
<Parameters Name="Launcher"></Parameters>
<Parameters Name="UseLauncher">False</Parameters>
/Tools/RC.Exe
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/Tools/RcDll.Dll
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Deleted: svn:mime-type
-application/octet-stream
\ No newline at end of property
/Tools/RemoveSignature.exe
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
/Tools/Sources.txt
6,6 → 6,3
 
upx.exe
http://upx.sourceforge.net/
 
rc.dll, rcdll.dll
Windows Server 2003 SP1 SDK
/ExtractorPassword.dfm
7,11 → 7,7
ClientHeight = 140
ClientWidth = 290
Color = clBtnFace
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
ParentFont = True
OldCreateOrder = True
Position = poMainFormCenter
OnShow = FormShow
20,7 → 16,7
object PwEnterLabel: TLabel
Left = 8
Top = 56
Width = 117
Width = 120
Height = 13
Caption = 'Bitte Passwort eingeben.'
end
27,7 → 23,7
object FileLabel: TLabel
Left = 8
Top = 6
Width = 28
Width = 29
Height = 13
Caption = 'Datei:'
end
/ExtractorComment.dfm
5,10 → 5,10
ClientHeight = 499
ClientWidth = 521
Color = clBtnFace
Font.Charset = ANSI_CHARSET
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
Position = poMainFormCenter
38,13 → 38,7
Height = 25
Caption = 'OK'
Default = True
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
ModalResult = 1
ParentFont = False
TabOrder = 0
end
object CancelBtn: TButton
54,13 → 48,7
Height = 25
Cancel = True
Caption = 'Abbrechen'
Font.Charset = ANSI_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
ModalResult = 2
ParentFont = False
TabOrder = 1
end
end
/ExtractorError.pas
2,11 → 2,10
 
interface
 
// TODO: Richtige Ordnerliste mit Icons anzeigen?
// TODO: Dialog sizeable
 
uses
Forms, StdCtrls, ExtCtrls, Controls, Graphics, Classes, Dialogs,
ZipMstr19, SysUtils;
Forms, StdCtrls, ExtCtrls, Controls, Graphics, Classes;
 
type
TErrorForm = class(TForm)
14,13 → 13,9
ErrorImg: TImage;
ErrorLabel: TLabel;
OKBtn: TButton;
SaveBtn: TButton;
SaveDialog: TSaveDialog;
procedure FormResize(Sender: TObject);
procedure SaveBtnClick(Sender: TObject);
public
function ErrorsAvailable: boolean;
procedure NewError(Filename: string; SkipType: TZMSkipTypes);
procedure NewError(Filename: string);
end;
 
var
30,58 → 25,15
 
{$R *.dfm}
 
function SkipTypeToStr(SkipType: TZMSkipTypes): string;
begin
case SkipType of
stOnFreshen: result := 'stOnFreshen';
stNoOverwrite: result := 'stNoOverwrite';
stFileExists: result := 'stFileExists';
stBadPassword: result := 'stBadPassword';
stBadName: result := 'stBadName';
stCompressionUnknown: result := 'stCompressionUnknown';
stUnknownZipHost: result := 'stUnknownZipHost';
stZipFileFormatWrong: result := 'stZipFileFormatWrong';
stGeneralExtractError: result := 'stGeneralExtractError';
stUser: result := 'stUser';
stCannotDo: result := 'stCannotDo';
stNotFound: result := 'stNotFound';
stNoShare: result := 'stNoShare';
stNoAccess: result := 'stNoAccess';
stNoOpen: result := 'stNoOpen';
stDupName: result := 'stDupName';
stReadError: result := 'stReadError';
stSizeChange: result := 'stSizeChange';
end;
end;
 
function TErrorForm.ErrorsAvailable: boolean;
begin
result := ErrorList.Items.Count > 0;
end;
 
procedure TErrorForm.FormResize(Sender: TObject);
procedure TErrorForm.NewError(Filename: string);
begin
ErrorList.Width := ClientWidth - ErrorList.Left - ErrorImg.Left;
ErrorList.Height := ClientHeight - ErrorList.Top - (2 * ErrorImg.Left + OkBtn.Height);
OkBtn.Top := ErrorList.Top + ErrorList.Height + ErrorImg.Left;
OkBtn.Left := ErrorList.Left + ErrorList.Width - OkBtn.Width;
SaveBtn.Top := OkBtn.Top;
end;
 
procedure TErrorForm.NewError(Filename: string; SkipType: TZMSkipTypes);
resourcestring
Lng_Err_Entry = '%s (Grund: %s)';
begin
// In future: Also add reason into list?
ErrorList.Items.Add(Format(Lng_Err_Entry, [Filename, SkipTypeToStr(SkipType)]));
ErrorList.Items.Add(Filename);
end;
 
procedure TErrorForm.SaveBtnClick(Sender: TObject);
begin
if SaveDialog.Execute then
begin
ErrorList.Items.SaveToFile(SaveDialog.FileName);
end;
end;
 
end.
/_PreBuild.bat
1,10 → 1,4
@echo off
 
rem brcc32 is not compatible with Vista icons
Tools\rc Extractor.rc
Tools\rc MakeSFX.rc
 
cd zmstr1900102\DLL\ResDLL-Maker\
call MakeResDll.bat
 
pause.
/Extractor.bdsproj
53,7 → 53,7
<Compiler Name="SymbolPlatform">True</Compiler>
<Compiler Name="SymbolExperimental">True</Compiler>
<Compiler Name="UnitLibrary">True</Compiler>
<Compiler Name="UnitPlatform">False</Compiler>
<Compiler Name="UnitPlatform">True</Compiler>
<Compiler Name="UnitDeprecated">True</Compiler>
<Compiler Name="UnitExperimental">True</Compiler>
<Compiler Name="HResultCompat">True</Compiler>
130,7 → 130,7
<Directories Name="UsePackages">False</Directories>
</Directories>
<Parameters>
<Parameters Name="RunParams">"Tests\128-Bit Enc.zip"</Parameters>
<Parameters Name="RunParams">helloworld.exe</Parameters>
<Parameters Name="HostApplication"></Parameters>
<Parameters Name="Launcher"></Parameters>
<Parameters Name="UseLauncher">False</Parameters>