SFX Builder
Angeregt durch diesen Thread
self extract, habe ich noch mal meine
SFX-Tools hervorgekramt und noch mal gänzlich neu programmiert. Nach vier Jahren mehr an Programmiererfahrung, sieht der Code doch etwas anderes aus.

Damals wollte ich nur wissen, wie so etwas gehen könnte und habe es mehr schlecht als recht auch hinbekommen. Der zweite Versuch, vier Jahre später, ist da schon besser gelungen, was das Design des Codes und den Code selber angeht.
Der SFX Builder besteht aus zwei Exe-Dateien, dem Builder selber, der das Archiv erstellt und der SFXStub an dem die Dateien angehangen werden und der den Code zum Entpacken beinhaltet. Der Code besteht aus drei zentralen Klassen:
Delphi-Quellcode:
TFile = class(TObject)
private
FFilename: String;
FFileSize: Int64;
FOffset: Int64;
function GetFilename: String;
procedure SetFilename(const Value: String);
function GetFileSize: Int64;
procedure SetFileSize(const Value: Int64);
function GetOffSet: Int64;
procedure SetOffSet(const Value: Int64);
public
property Filename: String read GetFilename write SetFilename;
property FileSize: Int64 read GetFileSize write SetFileSize;
property OffSet: Int64 read GetOffSet write SetOffSet;
end;
Die Klasse TFile repräsentiert eine Datei mit den Eigenschaften: Dateiname, -größe und Offset, der angibt an welcher Position sich die Datei im Archiv befindet. Damit wäre es ohne weiteres möglich eine Datei gezielt zu entpacken, ohne alle entpacken zu müssen.
Delphi-Quellcode:
TFileContainer = class(TList)
private
FFileList: TList;
FOffSet: Int64;
FTotalSize: Int64;
function GetItem(Index: Integer): TFile;
procedure SetItem(Index: Integer; FileObject: TFile);
public
constructor Create;
destructor Destroy; override;
property Items[Index: Integer]: TFile read GetItem write SetItem;
procedure Add(FileObject: TFile);
procedure Clear; override;
function Count: Integer;
property OffSet: Int64 read FOffSet write FOffSet;
property TotalSize: Int64 read FTotalSize write FTotalSize;
end;
Die Klasse TFileContainer verwaltet alle Objekte vom Typ TFile in einer Liste.
Delphi-Quellcode:
TTOCEntry = packed record
Filename: string[255];
FileSize: Int64;
OffSet: Int64;
end;
TOnAppendTOC = procedure(Sender: TObject) of object;
TOnAppendFile = procedure(Sender: TObject; Index: Integer; FileObject: TFile) of object;
TOnAppendingFile = procedure(Sender: TObject; FileObject: TFile; PercentDone: Integer) of object;
TOnExtractFile = procedure(Sender: TObject; Index: Integer; FileObject: TFile) of object;
TOnExtractingFile = procedure(Sender: TObject; FileObject: TFile; PercentDone: Integer) of object;
TSFX = class(TObject)
private
FFilename: string;
FStubFileSize: Integer;
FRoot: string;
FFileList: TFileContainer;
FTOC: array of TTOCEntry;
FCancel: Boolean;
FOnAppendTOC: TOnAppendTOC;
FOnAppendFile: TOnAppendFile;
FOnAppendingFile: TOnAppendingFile;
FOnExtractFile: TOnExtractFile;
FOnExtractingFile: TOnExtractingFile;
procedure CreateTOC;
public
constructor Create(Filename: string; Root: string; FileList: TFileContainer);
procedure AppendFiles;
procedure AppendTOC;
procedure ReadTOC;
procedure ExtractFiles;
procedure CopyStub(Source, Dest: string);
property Cancel: Boolean read FCancel write FCancel;
property OnAppendTOC: TOnAppendTOC read FOnAppendTOC write FOnAppendTOC;
property OnAppendFile: TOnAppendFile read FOnAppendFile write FOnAppendFile;
property OnAppendingFile: TOnAppendingFile read FOnAppendingFile write FOnAppendingFile;
property OnExtractFile: TOnExtractFile read FOnExtractFile write FOnExtractFile;
property OnExtractingFile: TOnExtractingFile read FOnExtractingFile write FOnExtractingFile;
end;
Und schließlich die Klasse TSFX selber, die das Erzeugen und das Entpacken des Archivs selber übernimmt. Beim Erstellen werden alle Dateien aus der Liste an die Exe zum Entpacken angehangen. Dann wird ein Inhaltsverzeichnis erstellt, welches nur ein dynamisches Array vom Typ TTOCEntry ist, welches dann auch angehangen wird. Und zum Schluss wird noch die Größe des Inhaltsverzeichnisses und die Größe der Exe zum Entpacken angehangen.
Das Extrahieren geschieht in umgekehrter Reihenfolge. Erst wird das Inhaltsverzeichnis gelesen, dann die Dateiliste erstellt und schliesslich werden an Hand der Dateiliste die Dateien extrahiert.
Das alles geschieht erstmal nur ohne Kompression, welche das ganze natürlich noch etwas verkompliziert. Ich muss mal sehen, ob ich mir noch die Mühe mache und mir dazu noch etwas einfallen lasse. Bis dahin, kann man das Projekt mehr als HowTo ansehen, als ein wirkliche Projekt, was von Nutzen ist. Desweiteren wäre zu überlegen, ob man noch eine Auswahl von Dateien beim Packen zulässt und es ermöglicht, gezielt nur ausgewählte Dateien zu extrahieren. Dazu müsste man beim Extrahieren die Klasse TSFX noch um eine Suchfunktion erweitern die eine bestimmte Datei im Archiv lokalisiert. Hat man sie erstmal gefunden, ist es kein Problem mehr sie zu extrahiere: Man kennt den Namen, die Größe und weiß an welcher Stelle im Archiv sie sich befindet an Hand des Offsets.
Bisher scheint alles zu funktionieren. Hat man allerdings ein sehr großes Archiv erstellt, meherer MB, mus sman eine weile warten, weil das Betriebssytem anscheinend eine Weile braucht, um alle offnen
Handle zu schliessen, warum auch immer.
Ihr könnt es euch ja mal angucken. Allerdings Featurerequests werde ich erstmal nichtannehmen, da das ganze für mich erst mal nur ein HowTo ist. Hinzukommt, dass jedes herkömmliche Packprogramm selbst-entpackende Archive erstellen kann und das wahrscheinlich besser und effizienter, als ich es hinbekommen würde.
Ein Teil meines Codes würde euch verunsichern.