|
- unit uvfsZipArchive;
-
- interface
-
- uses
- SysUtils, Classes, uvfsManager, KAZip, syncobjs;
-
- type
-
- { TvfsZipArchive }
-
- TvfsZipArchive = class(TvfsProvider)
- private
- FZipActionCS: TCriticalSection;
- FZipper: TKAZip;
- procedure Flush(Handle: TvfsStreamHandleWrite; Data: Pointer; DataSize: integer);
- function PrepareFilename(const aFilename: String): String;
- public
- constructor Create(const FileSpec:string; const ExtendedData: string=''); override;
- destructor Destroy; override;
- class function StorageName: string; override;
- function StorageGetFileSpec: string; override;
- function GetFileInfo(const FileName: string; out FileInfo: TvfsFileInfo): Boolean; override;
- function Open(const FileName: string; const OpenMode: TvfsFileOpenMode; out Stream: IStreamHandle): boolean; override;
- function Rename(const OldName, NewName: string): boolean; override;
- function Delete(const aName: String): boolean; override;
- procedure DirectoryIndex(AddFunction: TvfsDirectoryAddFunc; List: TvfsDirectoryList; Path: string; Subdirs: boolean); override;
-
- function ZipFilename: string;
- end;
-
- implementation
-
- { TvfsZipArchive }
-
- constructor TvfsZipArchive.Create(const FileSpec: string; const ExtendedData: string);
- var
- path: String;
- dir: String;
- begin
- inherited;
- FZipActionCS := TCriticalSection.Create;
- FZipper:= TKAZip.Create(nil);
- path := vfsSystemPathDelim(FileSpec);
- if not FileExists(path) then begin
- dir := ExtractFilePath(path);
- if (dir <> '') then
- ForceDirectories(dir);
- FZipper.CreateZip(path);
- end;
- FZipper.Open(path);
- FZipper.CompressionType:= ctNone;
- end;
-
- destructor TvfsZipArchive.Destroy;
- begin
- if Assigned(FZipper) then begin
- FZipActionCS.Acquire;
- try
- FreeAndNil(FZipper);
- finally
- FZipActionCS.Release;
- end;
- end;
- FreeAndNil(FZipActionCS);
- inherited;
- end;
-
- class function TvfsZipArchive.StorageName: string;
- begin
- Result:= 'zip';
- end;
-
- function TvfsZipArchive.StorageGetFileSpec: string;
- begin
- Result:= Self.ZipFileName;
- end;
-
- procedure TvfsZipArchive.DirectoryIndex(AddFunction: TvfsDirectoryAddFunc; List: TvfsDirectoryList; Path: string; Subdirs: boolean);
- var
- i: integer;
- a: TvfsDirectoryEntry;
- e: TKAZipEntriesEntry;
- fp: string;
- dirOk: boolean;
- begin
- FZipActionCS.Acquire;
- try
- for i:= 0 to FZipper.Entries.Count-1 do begin
- e:= FZipper.Entries.Items[i];
- fp:= FZipper.GetFilePath(e.FileName);
- if Subdirs then
- dirOk:= 0=AnsiCompareStr(Path, Copy(fp, 1, Length(Path)))
- else
- dirOk:= 0=AnsiCompareFileName(Path, fp);
- if dirOk then begin
- a:= TvfsDirectoryEntry.Create;
- a.FileInfo.Size:= e.SizeUncompressed;
- a.FileInfo.Attributes:= e.Attributes;
- a.FileInfo.ModDate:= e.Date;
- AddFunction(fp+FZipper.GetFileName(e.FileName), a, List);
- end;
- end;
- finally
- FZipActionCS.Release;
- end;
- end;
-
- function TvfsZipArchive.GetFileInfo(const FileName: string; out FileInfo: TvfsFileInfo): Boolean;
- var
- i:integer;
- begin
- FZipActionCS.Acquire;
- try
- i:= FZipper.Entries.IndexOf(PrepareFilename(vfsSystemPathDelim(FileName)));
- Result:= i>=0;
- if Result then begin
- FileInfo.Size:= FZipper.Entries.Items[i].SizeUncompressed;
- FileInfo.Attributes:= FZipper.Entries.Items[i].Attributes;
- FileInfo.ModDate:= FZipper.Entries.Items[i].Date;
- end;
- finally
- FZipActionCS.Release;
- end;
- end;
-
- function TvfsZipArchive.Open(const FileName: string; const OpenMode: TvfsFileOpenMode; out Stream: IStreamHandle): boolean;
- var
- ms: TMemoryStream;
- eid: Integer;
- begin
- ms:= nil;
- Stream:= nil;
- Result:= false;
- try
- FZipActionCS.Acquire;
- try
- eid:= FZipper.Entries.IndexOf(PrepareFilename(vfsSystemPathDelim(FileName)));
-
- if (eid>=0) and (OpenMode<>omCreateAlways) then begin
- ms:= TMemoryStream.Create;
- FZipper.Entries.Items[eid].ExtractToStream(ms);
- end;
- finally
- FZipActionCS.Release;
- end;
-
- case OpenMode of
- omReadOnly: if Assigned(ms) then begin
- ms.Position:= 0;
- Stream:= TvfsStreamHandleRead.Create(ms);
- end;
- omReadWrite: if Assigned(ms) then begin
- ms.Position:= ms.Size;
- Stream:= TvfsStreamHandleWrite.Create(ms, @Self.Flush, PChar(FileName), 1+strlen(PChar(FileName)));
- end;
- omReadWriteCreate: begin
- if not Assigned(ms) then
- ms:= TMemoryStream.Create;
- ms.Position:= ms.Size;
- Stream:= TvfsStreamHandleWrite.Create(ms, @Self.Flush, PChar(FileName), 1+strlen(PChar(FileName)));
- end;
- omCreateAlways: begin
- ms:= TMemoryStream.Create;
- Stream:= TvfsStreamHandleWrite.Create(ms, @Self.Flush, PChar(FileName), 1+strlen(PChar(FileName)));
- end;
- end;
- Result:= Assigned(Stream);
- if not Result then
- FreeAndNil(ms);
- except
- FreeAndNil(ms);
- raise;
- end;
- end;
-
- function TvfsZipArchive.Rename(const OldName, NewName: string): boolean;
- begin
- FZipActionCS.Acquire;
- try
- if FZipper.Entries.IndexOf(OldName)>=0 then
- FZipper.Rename(OldName, NewName)
- else
- FZipper.RenameFolder(OldName, NewName);
- finally
- FZipActionCS.Release;
- end;
- Result:= true;
- end;
-
- function TvfsZipArchive.Delete(const aName: String): boolean;
- begin
- //TODO: delete file from zip
- Result:= false;
- raise Exception.Create('not yet implemented');
- end;
-
- procedure TvfsZipArchive.Flush(Handle: TvfsStreamHandleWrite; Data: Pointer; DataSize: integer);
- var s:string;
- begin
- s:= StrPas(Data);
- Handle.GetStream.Position:= 0;
- FZipActionCS.Acquire;
- try
- FZipper.AddStream(s, Handle.GetStream);
- finally
- FZipActionCS.Release;
- end;
- end;
-
- function TvfsZipArchive.PrepareFilename(const aFilename: String): String;
- var
- sl: TStringList;
- i: Integer;
- begin
- sl := TStringList.Create;
- try
- sl.Delimiter := PathDelim;
- sl.StrictDelimiter := true;
- sl.DelimitedText := aFilename;
- i := 0;
- while (i < sl.Count) do begin
- if (sl[i] = '..') and (i > 0) then begin
- sl.Delete(i);
- dec(i);
- sl.Delete(i);
- end else
- inc(i);
- end;
- result := sl.DelimitedText;
- finally
- FreeAndNil(sl);
- end;
- end;
-
- function TvfsZipArchive.ZipFilename: string;
- begin
- Result:= FZipper.FileName;
- end;
-
- initialization
- vfsManager.RegisterProvider(TvfsZipArchive);
- end.
|