Browse Source

* Added possibility to set filename in archive, and added possibility to use streams

git-svn-id: trunk@11833 -
michael 17 years ago
parent
commit
7e5340c07c
1 changed files with 249 additions and 127 deletions
  1. 249 127
      packages/paszlib/src/zipper.pp

+ 249 - 127
packages/paszlib/src/zipper.pp

@@ -119,14 +119,6 @@ Const
 
 Type
 
-  TZipItem   = Class(TObject)
-    Path : String;
-    Name : String;
-    Size : LongInt;
-    DateTime : TDateTime;
-    HdrPos : Longint;
-  end;
-
   TProgressEvent = Procedure(Sender : TObject; Const Pct : Double) of object;
   TOnEndOfFileEvent = Procedure(Sender : TObject; Const Ratio : Double) of object;
   TOnStartFileEvent = Procedure(Sender : TObject; Const AFileName : String) of object;
@@ -260,17 +252,54 @@ Type
     Class Function ZipID : Word; override;
   end;
 
+  { TZipFileEntry }
+
+  TZipFileEntry = Class(TCollectionItem)
+  private
+    FArchiveFileName: String;
+    FDateTime: TDateTime;
+    FDiskFileName: String;
+    FHeaderPos: Longint;
+    FSize: Integer;
+    FStream: TStream;
+    function GetArchiveFileName: String;
+  Protected
+    Property HdrPos : Longint Read FHeaderPos Write FheaderPos;
+  Public
+    Property Stream : TStream Read FStream Write FStream;
+  Published
+    Property ArchiveFileName : String Read GetArchiveFileName Write FArchiveFileName;
+    Property DiskFileName : String Read FDiskFileName Write FDiskFileName;
+    Property Size : Integer Read FSize Write FSize;
+    Property DateTime : TDateTime Read FDateTime Write FDateTime;
+  end;
+
+  { TZipFileEntries }
+
+  TZipFileEntries = Class(TCollection)
+  private
+    function GetZ(AIndex : Integer): TZipFileEntry;
+    procedure SetZ(AIndex : Integer; const AValue: TZipFileEntry);
+  Public
+    Function AddFileEntry(Const ADiskFileName : String): TZipFileEntry;
+    Function AddFileEntry(Const ADiskFileName, AArchiveFileName : String): TZipFileEntry;
+    Function AddFileEntry(Const AStream : TSTream; Const AArchiveFileName : String): TZipFileEntry;
+    Property Entries[AIndex : Integer] : TZipFileEntry Read GetZ Write SetZ; default;
+  end;
+
+
   { TZipper }
 
   TZipper = Class(TObject)
   Private
+    FEntries: TZipFileEntries;
     FZipping    : Boolean;
     FBufSize    : LongWord;
     FFileName   :  String;         { Name of resulting Zip file                 }
     FFiles      : TStrings;
     FInMemSize  : Integer;
     FOutFile    : TFileStream;
-    FInFile     : TFileStream;     { I/O file variables                         }
+    FInFile     : TStream;     { I/O file variables                         }
     LocalHdr    : Local_File_Header_Type;
     CentralHdr  : Central_File_Header_Type;
     EndHdr      : End_of_Central_Dir_Type;
@@ -278,25 +307,28 @@ Type
     FOnProgress : TProgressEvent;
     FOnEndOfFile : TOnEndOfFileEvent;
     FOnStartFile : TOnStartFileEvent;
+    function CheckEntries: Integer;
+    procedure SetEntries(const AValue: TZipFileEntries);
   Protected
     Procedure OpenOutput;
     Procedure CloseOutput;
-    Procedure CloseInput;
-    Procedure StartZipFile(Item : TZipItem);
-    Function  UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord;AMethod : Word) : Boolean;
+    Procedure CloseInput(Item : TZipFileEntry);
+    Procedure StartZipFile(Item : TZipFileEntry);
+    Function  UpdateZipHeader(Item : TZipFileEntry; FZip : TStream; ACRC : LongWord;AMethod : Word) : Boolean;
     Procedure BuildZipDirectory;
     Procedure DoEndOfFile;
-    Procedure ZipOneFile(Item : TZipItem); virtual;
-    Function  OpenInput(InFileName : String) : Boolean;
+    Procedure ZipOneFile(Item : TZipFileEntry); virtual;
+    Function  OpenInput(Item : TZipFileEntry) : Boolean;
     Procedure GetFileInfo;
     Procedure SetBufSize(Value : LongWord);
     Procedure SetFileName(Value : String);
-    Function CreateCompressor(Item : TZipItem; AinFile,AZipStream : TStream) : TCompressor; virtual;
+    Function CreateCompressor(Item : TZipFileEntry; AinFile,AZipStream : TStream) : TCompressor; virtual;
   Public
     Constructor Create;
     Destructor Destroy;override;
     Procedure ZipAllFiles; virtual;
     Procedure ZipFiles(AFileName : String; FileList : TStrings);
+    Procedure ZipFiles(AFileName : String; Entries : TZipFileEntries);
     Procedure Clear;
   Public
     Property BufferSize : LongWord Read FBufSize Write SetBufSize;
@@ -307,6 +339,7 @@ Type
     Property FileName : String Read FFileName Write SetFileName;
     Property Files : TStrings Read FFiles;
     Property InMemSize : Integer Read FInMemSize Write FInMemSize;
+    Property Entries : TZipFileEntries Read FEntries Write SetEntries;
   end;
 
   { TYbZipper }
@@ -319,8 +352,8 @@ Type
     FBufSize    : LongWord;
     FFileName   :  String;         { Name of resulting Zip file                 }
     FOutputPath : String;
+    FEntries    : TZipFileEntries;
     FFiles      : TStrings;
-    FZipEntries : TFPList;  { don't use TFPObjectList, becuase of Contnrs dependency }
     FOutFile    : TFileStream;
     FZipFile     : TFileStream;     { I/O file variables                         }
     LocalHdr    : Local_File_Header_Type;
@@ -335,15 +368,15 @@ Type
     Procedure OpenInput;
     Procedure CloseOutput;
     Procedure CloseInput;
-    Procedure ReadZipHeader(Item : TZipItem; out ACRC : LongWord;out AMethod : Word);
+    Procedure ReadZipHeader(Item : TZipFileEntry; out ACRC : LongWord;out AMethod : Word);
     Procedure ReadZipDirectory;
     Procedure DoEndOfFile;
-    Procedure UnZipOneFile(Item : TZipItem); virtual;
+    Procedure UnZipOneFile(Item : TZipFileEntry); virtual;
     Function  OpenOutput(OutFileName : String) : Boolean;
     Procedure SetBufSize(Value : LongWord);
     Procedure SetFileName(Value : String);
     Procedure SetOutputPath(Value:String);
-    Function CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor; virtual;
+    Function CreateDeCompressor(Item : TZipFileEntry; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor; virtual;
   Public
     Constructor Create;
     Destructor Destroy;override;
@@ -360,6 +393,7 @@ Type
     Property FileName : String Read FFileName Write SetFileName;
     Property OutputPath : String Read FOutputPath Write SetOutputPath;
     Property Files : TStrings Read FFiles;
+    Property Entries : TZipFileEntries Read FEntries Write FEntries;
   end;
 
   EZipError = Class(Exception);
@@ -372,6 +406,9 @@ ResourceString
   SErrInvalidCRC = 'Invalid CRC checksum while unzipping %s';
   SErrCorruptZIP = 'Corrupt ZIP file %s';
   SErrUnsupportedCompressionFormat = 'Unsupported compression format %d';
+  SErrMissingFileName = 'Missing filename in entry %d';
+  SErrMissingArchiveName = 'Missing archive filename in streamed entry %d';
+  SErrFileDoesNotExist = 'File "%s" does not exist.';
 
 { ---------------------------------------------------------------------
     Auxiliary
@@ -907,26 +944,42 @@ end;
 Procedure TZipper.GetFileInfo;
 
 Var
-   Info : TSearchRec;
-   I       : Longint;
-   NewNode : TZipItem;
-
+  F : TZipFileEntry;
+  Info : TSearchRec;
+  I       : Longint;
 
 Begin
-   For I := 0 to FFiles.Count-1 do
+  For I := 0 to FEntries.Count-1 do
     begin
-     If FindFirst(FFiles[I], STDATTR, Info)=0 then
-       try
-         NewNode:=TZipItem.Create;
-         NewNode.Path := ExtractFilePath(FFiles[i]);
-         NewNode.Name := Info.Name;
-         NewNode.Size := Info.Size;
-         NewNode.DateTime:=FileDateToDateTime(Info.Time);
-         FFiles.Objects[i]:=NewNode;
-       finally
-         FindClose(Info);
-       end;
-     end;
+    F:=FEntries[i];
+    If F.Stream=Nil then
+      begin
+      If (F.DiskFileName='') then
+        Raise EZipError.CreateFmt(SErrMissingFileName,[I]);
+      If FindFirst(F.DiskFileName, STDATTR, Info)=0 then
+        try
+          F.Size:=Info.Size;
+          F.DateTime:=FileDateToDateTime(Info.Time);
+        finally
+          FindClose(Info);
+        end
+      else
+        Raise EZipError.CreateFmt(SErrFileDoesNotExist,[F.DiskFileName]);
+      end
+    else
+      begin
+      If (F.ArchiveFileName='') then
+        Raise EZipError.CreateFmt(SErrMissingArchiveName,[I]);
+      F.Size:=F.Stream.Size;
+      end;
+    end;
+end;
+
+
+procedure TZipper.SetEntries(const AValue: TZipFileEntries);
+begin
+  if FEntries=AValue then exit;
+  FEntries.Assign(AValue);
 end;
 
 Procedure TZipper.OpenOutput;
@@ -936,13 +989,16 @@ Begin
 End;
 
 
-Function TZipper.OpenInput(InFileName : String) : Boolean;
+Function TZipper.OpenInput(Item : TZipFileEntry) : Boolean;
 
 Begin
-  FInFile:=TFileStream.Create(InFileName,fmOpenRead);
+  If (Item.Stream<>nil) then
+    FInFile:=Item.Stream
+  else
+    FInFile:=TFileStream.Create(Item.DiskFileName,fmOpenRead);
   Result:=True;
   If Assigned(FOnStartFile) then
-    FOnStartFile(Self,InFileName);
+    FOnStartFile(Self,Item.ArchiveFileName);
 End;
 
 
@@ -953,14 +1009,17 @@ Begin
 end;
 
 
-Procedure TZipper.CloseInput;
+Procedure TZipper.CloseInput(Item : TZipFileEntry);
 
 Begin
-  FreeAndNil(FInFile);
+  If (FInFile<>Item.Stream) then
+    FreeAndNil(FInFile)
+  else
+    FinFile:=Nil;
 end;
 
 
-Procedure TZipper.StartZipFile(Item : TZipItem);
+Procedure TZipper.StartZipFile(Item : TZipFileEntry);
 
 Begin
   FillChar(LocalHdr,SizeOf(LocalHdr),0);
@@ -980,11 +1039,11 @@ Begin
 End;
 
 
-Function TZipper.UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord; AMethod : Word) : Boolean;
+Function TZipper.UpdateZipHeader(Item : TZipFileEntry; FZip : TStream; ACRC : LongWord; AMethod : Word) : Boolean;
 var
   ZFileName  : ShortString;
 Begin
-  ZFileName:=Item.Path+Item.Name;
+  ZFileName:=Item.ArchiveFileName;
   With LocalHdr do
     begin
     FileName_Length := Length(ZFileName);
@@ -1009,11 +1068,11 @@ Var
    SavePos   : LongInt;
    HdrPos    : LongInt;
    CenDirPos : LongInt;
-   Entries   : Word;
+   ACount    : Word;
    ZFileName  : ShortString;
 
 Begin
-   Entries := 0;
+   ACount := 0;
    CenDirPos := FOutFile.Position;
    FOutFile.Seek(0,soFrombeginning);             { Rewind output file }
    HdrPos := FOutFile.Position;
@@ -1039,7 +1098,7 @@ Begin
      FOutFile.Seek(0,soFromEnd);
      FOutFile.WriteBuffer(CentralHdr,SizeOf(CentralHdr));
      FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
-     Inc(Entries);
+     Inc(ACount);
      FOutFile.Seek(SavePos + LocalHdr.Compressed_Size,soFromBeginning);
      HdrPos:=FOutFile.Position;
      FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
@@ -1051,8 +1110,8 @@ Begin
      Signature := END_OF_CENTRAL_DIR_SIGNATURE;
      Disk_Number := 0;
      Central_Dir_Start_Disk := 0;
-     Entries_This_Disk := Entries;
-     Total_Entries := Entries;
+     Entries_This_Disk := ACount;
+     Total_Entries := ACount;
      Central_Dir_Size := FOutFile.Size-CenDirPos;
      Start_Disk_Offset := CenDirPos;
      ZipFile_Comment_Length := 0;
@@ -1060,13 +1119,13 @@ Begin
      end;
 end;
 
-Function TZipper.CreateCompressor(Item : TZipItem; AInFile,AZipStream : TStream) : TCompressor;
+Function TZipper.CreateCompressor(Item : TZipFileEntry; AInFile,AZipStream : TStream) : TCompressor;
 
 begin
   Result:=TDeflater.Create(AinFile,AZipStream,FBufSize);
 end;
 
-Procedure TZipper.ZipOneFile(Item : TZipItem);
+Procedure TZipper.ZipOneFile(Item : TZipFileEntry);
 
 Var
   CRC : LongWord;
@@ -1075,7 +1134,7 @@ Var
   TmpFileName : String;
 
 Begin
-  OpenInput(Item.Path+Item.Name);
+  OpenInput(Item);
   Try
     StartZipFile(Item);
     If (FInfile.Size<=FInMemSize) then
@@ -1111,32 +1170,28 @@ Begin
         DeleteFile(TmpFileName);
     end;
   Finally
-    CloseInput;
+    CloseInput(Item);
   end;
 end;
 
 Procedure TZipper.ZipAllFiles;
+
 Var
-   Item : TZipItem;
    I : Integer;
    filecnt : integer;
 Begin
-  if FFiles.Count=0 then
-    exit;
+  If CheckEntries=0 then
+    Exit;
   FZipping:=True;
   Try
     GetFileInfo;
     OpenOutput;
     Try
       filecnt:=0;
-      For I:=0 to FFiles.Count-1 do
+      For I:=0 to FEntries.Count-1 do
         begin
-          Item:=FFiles.Objects[i] as TZipItem;
-          if assigned(Item) then
-            begin
-              ZipOneFile(Item);
-              inc(filecnt);
-            end;
+        ZipOneFile(FEntries[i]);
+        inc(filecnt);
         end;
       if filecnt>0 then
         BuildZipDirectory;
@@ -1174,6 +1229,13 @@ begin
   ZipAllFiles;
 end;
 
+procedure TZipper.ZipFiles(AFileName: String; Entries: TZipFileEntries);
+begin
+  FFileName:=AFileName;
+  FEntries.Assign(Entries);
+  ZipAllFiles;
+end;
+
 Procedure TZipper.DoEndOfFile;
 
 Var
@@ -1194,18 +1256,32 @@ begin
   FBufSize:=DefaultBufSize;
   FInMemSize:=DefaultInMemSize;
   FFiles:=TStringList.Create;
-  TStringlist(FFiles).Sorted:=True;
+  FEntries:=TZipFileEntries.Create(TZipFileEntry);
   FOnPercent:=1;
 end;
 
-Procedure TZipper.Clear;
+Function TZipper.CheckEntries : Integer;
 
 Var
   I : Integer;
 
 begin
-  For I:=0 to FFiles.Count-1 do
-    FFiles.Objects[i].Free;
+  If (FFiles.Count>0) and (FEntries.Count=0) then
+    begin
+    FEntries.Clear;
+    For I:=0 to FFiles.Count-1 do
+      begin
+      FEntries.AddFileEntry(FFiles[i]);
+      end;
+    end;
+  Result:=FEntries.Count;
+end;
+
+
+Procedure TZipper.Clear;
+
+begin
+  FEntries.Clear;
   FFiles.Clear;
 end;
 
@@ -1213,6 +1289,7 @@ Destructor TZipper.Destroy;
 
 begin
   Clear;
+  FreeAndNil(FEntries);
   FreeAndNil(FFiles);
   Inherited;
 end;
@@ -1254,20 +1331,27 @@ Begin
 end;
 
 
-Procedure TUnZipper.ReadZipHeader(Item : TZipItem; out ACRC : LongWord; out AMethod : Word);
+Procedure TUnZipper.ReadZipHeader(Item : TZipFileEntry; out ACRC : LongWord; out AMethod : Word);
+
+Var
+  S : String;
+  D : TDateTime;
 
 Begin
   FZipFile.Seek(Item.HdrPos,soFromBeginning);
   FZipFile.ReadBuffer(LocalHdr,SizeOf(LocalHdr));
   With LocalHdr do
     begin
-      SetLength(Item.Name,Filename_Length);
-      FZipFile.ReadBuffer(Item.Name[1],Filename_Length);
-      FZipFile.Seek(Extra_Field_Length,soCurrent);
-      Item.Size:=Uncompressed_Size;
-      ZipDateTimeToDateTime(Last_Mod_Date,Last_Mod_Time,Item.DateTime);
-      ACrc:=Crc32;
-      AMethod:=Compress_method;
+    SetLength(S,Filename_Length);
+    FZipFile.ReadBuffer(S[1],Filename_Length);
+    FZipFile.Seek(Extra_Field_Length,soCurrent);
+    Item.ArchiveFileName:=S;
+    Item.DiskFileName:=S;
+    Item.Size:=Uncompressed_Size;
+    ZipDateTimeToDateTime(Last_Mod_Date,Last_Mod_Time,D);
+    Item.DateTime:=D;
+    ACrc:=Crc32;
+    AMethod:=Compress_method;
     end;
 End;
 
@@ -1275,41 +1359,43 @@ End;
 Procedure TUnZipper.ReadZipDirectory;
 
 Var
-   i,
-   EndHdrPos,
-   CenDirPos : LongInt;
-   NewNode   : TZipItem;
+  i,
+  EndHdrPos,
+  CenDirPos : LongInt;
+  NewNode   : TZipFileEntry;
+  S : String;
+
 Begin
-   EndHdrPos:=FZipFile.Size-SizeOf(EndHdr);
-   if EndHdrPos < 0 then
-     raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
-   FZipFile.Seek(EndHdrPos,soFromBeginning);
-   FZipFile.ReadBuffer(EndHdr, SizeOf(EndHdr));
-   With EndHdr do
-     begin
-       if Signature <> END_OF_CENTRAL_DIR_SIGNATURE then
-         raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
-       CenDirPos:=Start_Disk_Offset;
-     end;
-   FZipFile.Seek(CenDirPos,soFrombeginning);
-   for i:=0 to EndHdr.Entries_This_Disk-1 do
-     begin
-       FZipFile.ReadBuffer(CentralHdr, SizeOf(CentralHdr));
-       With CentralHdr do
-         begin
-           if Signature<>CENTRAL_FILE_HEADER_SIGNATURE then
-             raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
-           NewNode:=TZipItem.Create;
-           NewNode.HdrPos := Local_Header_Offset;
-           SetLength(NewNode.Name,Filename_Length);
-           FZipFile.ReadBuffer(NewNode.Name[1],Filename_Length);
-           FZipFile.Seek(Extra_Field_Length+File_Comment_Length,soCurrent);
-           FZipEntries.Add(NewNode);
-         end;
-     end;
+  EndHdrPos:=FZipFile.Size-SizeOf(EndHdr);
+  if EndHdrPos < 0 then
+    raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
+  FZipFile.Seek(EndHdrPos,soFromBeginning);
+  FZipFile.ReadBuffer(EndHdr, SizeOf(EndHdr));
+  With EndHdr do
+    begin
+    if Signature <> END_OF_CENTRAL_DIR_SIGNATURE then
+      raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
+    CenDirPos:=Start_Disk_Offset;
+    end;
+  FZipFile.Seek(CenDirPos,soFrombeginning);
+  for i:=0 to EndHdr.Entries_This_Disk-1 do
+    begin
+    FZipFile.ReadBuffer(CentralHdr, SizeOf(CentralHdr));
+    With CentralHdr do
+      begin
+      if Signature<>CENTRAL_FILE_HEADER_SIGNATURE then
+        raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
+      NewNode:=FEntries.Add as TZipFileEntry;
+      NewNode.HdrPos := Local_Header_Offset;
+      SetLength(S,Filename_Length);
+      FZipFile.ReadBuffer(S[1],Filename_Length);
+      NewNode.ArchiveFileName:=S;
+      FZipFile.Seek(Extra_Field_Length+File_Comment_Length,soCurrent);
+      end;
+   end;
 end;
 
-Function TUnZipper.CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor;
+Function TUnZipper.CreateDeCompressor(Item : TZipFileEntry; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor;
 begin
   case AMethod of
     8 :
@@ -1319,7 +1405,7 @@ begin
   end;
 end;
 
-Procedure TUnZipper.UnZipOneFile(Item : TZipItem);
+Procedure TUnZipper.UnZipOneFile(Item : TZipFileEntry);
 
 Var
   Count : Longint;
@@ -1329,7 +1415,7 @@ Var
 Begin
   Try
     ReadZipHeader(Item,CRC,ZMethod);
-    OutputFileName:=Item.Name;
+    OutputFileName:=Item.DiskFileName;
     if FOutputPath<>'' then
       OutputFileName:=IncludeTrailingPathDelimiter(FOutputPath)+OutputFileName;
     OpenOutput(OutputFileName);
@@ -1345,7 +1431,7 @@ Begin
           OnPercent:=Self.OnPercent;
           DeCompress;
           if CRC<>Crc32Val then
-            raise EZipError.CreateFmt(SErrInvalidCRC,[Item.Name]);
+            raise EZipError.CreateFmt(SErrInvalidCRC,[Item.ArchiveFileName]);
         Finally
           Free;
         end;
@@ -1357,9 +1443,10 @@ end;
 
 Procedure TUnZipper.UnZipAllFiles;
 Var
-   Item : TZipItem;
+   Item : TZipFileEntry;
    I : Integer;
    AllFiles : Boolean;
+
 Begin
   FUnZipping:=True;
   Try
@@ -1367,15 +1454,14 @@ Begin
     OpenInput;
     Try
       ReadZipDirectory;
-      For I:=0 to FZipEntries.Count-1 do
+      For I:=0 to FEntries.Count-1 do
         begin
-          Item:=TZipItem(FZipEntries[i]);
-          if AllFiles or
-             (FFiles.IndexOf(Item.Name)<>-1) then
-            UnZipOneFile(Item);
+        Item:=FEntries[i];
+        if AllFiles or (FFiles.IndexOf(Item.ArchiveFileName)<>-1) then
+          UnZipOneFile(Item);
         end;
     Finally
-       CloseInput;
+      CloseInput;
     end;
   finally
     FUnZipping:=False;
@@ -1441,23 +1527,16 @@ Constructor TUnZipper.Create;
 begin
   FBufSize:=DefaultBufSize;
   FFiles:=TStringList.Create;
-  FZipEntries:=TFPList.Create;
   TStringlist(FFiles).Sorted:=True;
+  FEntries:=TZipFileEntries.Create(TZipFileEntry);
   FOnPercent:=1;
 end;
 
 Procedure TUnZipper.Clear;
 
-Var
-  I : Integer;
-
 begin
-  For I:=0 to FFiles.Count-1 do
-    FFiles.Objects[i].Free;
   FFiles.Clear;
-  For I:=0 to FZipEntries.Count-1 do
-    TZipItem(FZipEntries[i]).Free;
-  FZipEntries.Clear;
+  FEntries.Clear;
 end;
 
 Destructor TUnZipper.Destroy;
@@ -1465,8 +1544,51 @@ Destructor TUnZipper.Destroy;
 begin
   Clear;
   FreeAndNil(FFiles);
-  FreeAndNil(FZipEntries);
+  FreeAndNil(FEntries);
   Inherited;
 end;
 
+{ TZipFileEntry }
+
+function TZipFileEntry.GetArchiveFileName: String;
+begin
+  Result:=FArchiveFileName;
+  If (Result='') then
+    Result:=FDiskFileName;
+end;
+
+{ TZipFileEntries }
+
+function TZipFileEntries.GetZ(AIndex : Integer): TZipFileEntry;
+begin
+  Result:=TZipFileEntry(Items[AIndex]);
+end;
+
+procedure TZipFileEntries.SetZ(AIndex : Integer; const AValue: TZipFileEntry);
+begin
+  Items[AIndex]:=AValue;
+end;
+
+function TZipFileEntries.AddFileEntry(const ADiskFileName: String
+  ): TZipFileEntry;
+begin
+  Result:=Add as TZipFileEntry;
+  Result.DiskFileName:=ADiskFileName;
+end;
+
+function TZipFileEntries.AddFileEntry(const ADiskFileName,
+  AArchiveFileName: String): TZipFileEntry;
+begin
+  Result:=AddFileEntry(ADiskFileName);
+  Result.ArchiveFileName:=AArchiveFileName;
+end;
+
+function TZipFileEntries.AddFileEntry(const AStream: TSTream;
+  const AArchiveFileName: String): TZipFileEntry;
+begin
+  Result:=Add as TZipFileEntry;
+  Result.Stream:=AStream;
+  Result.ArchiveFileName:=AArchiveFileName;
+end;
+
 End.