diff options
| author | michael <michael@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2008-09-28 14:35:28 +0000 |
|---|---|---|
| committer | michael <michael@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2008-09-28 14:35:28 +0000 |
| commit | 1e67b2dafb2f3defdfc0280920432392e76154eb (patch) | |
| tree | df90d5f08714ec9f89c38dce7e94ce6017d446fc /packages/paszlib/src | |
| parent | 1ddbd401e679143bd6f6bca3a72167a09c19902b (diff) | |
| download | fpc-1e67b2dafb2f3defdfc0280920432392e76154eb.tar.gz | |
* Added possibility to set filename in archive, and added possibility to use streams
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@11833 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'packages/paszlib/src')
| -rw-r--r-- | packages/paszlib/src/zipper.pp | 376 |
1 files changed, 249 insertions, 127 deletions
diff --git a/packages/paszlib/src/zipper.pp b/packages/paszlib/src/zipper.pp index 9daac71bd6..ac6a164118 100644 --- a/packages/paszlib/src/zipper.pp +++ b/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. |
