📄 sxziputils.pas
字号:
unit SXZipUtils;
////////////////////////////////////////////////////////////////////////////////
// SXSkinComponents: Skinnable Visual Controls for Delphi and C++Builder //
//----------------------------------------------------------------------------//
// Version: 1.2.1 //
// Author: Alexey Sadovnikov //
// Web Site: http://www.saarixx.info/sxskincomponents/ //
// E-Mail: sxskincomponents@saarixx.info //
//----------------------------------------------------------------------------//
// LICENSE: //
// 1. You may freely distribute this file. //
// 2. You may not make any changes to this file. //
// 3. The only person who may change this file is Alexey Sadovnikov. //
// 4. You may use this file in your freeware projects. //
// 5. If you want to use this file in your shareware or commercial project, //
// you should purchase a project license or a personal license of //
// SXSkinComponents: http://saarixx.info/sxskincomponents/en/purchase.htm //
// 6. You may freely use, distribute and modify skins for SXSkinComponents. //
// 7. You may create skins for SXSkinComponents. //
//----------------------------------------------------------------------------//
// Copyright (C) 2006-2007, Alexey Sadovnikov. All Rights Reserved. //
////////////////////////////////////////////////////////////////////////////////
interface
{$I Compilers.inc}
uses SysUtils, Classes, Types, Windows;
type
TCommonFileHeader=packed record
VersionNeededToExtract:Word;
GeneralPurposeBitFlag:Word;
CompressionMethod:Word;
LastModFileTimeDate:DWORD;
Crc32:DWORD;
CompressedSize:DWORD;
UncompressedSize:DWORD;
FilenameLength:Word;
ExtraFieldLength:Word;
end;
TLocalFile=packed record
LocalFileHeaderSignature:DWORD;
CommonFileHeader:TCommonFileHeader;
FileName:String;
ExtraField:String;
CompressedData:String;
end;
TFileHeader=packed record
CentralFileHeaderSignature:DWORD;
VersionMadeBy:Word;
CommonFileHeader:TCommonFileHeader;
FileCommentLength:Word;
DiskNumberStart:Word;
InternalFileAttributes:Word;
ExternalFileAttributes:DWORD;
RelativeOffsetOfLocalHeader:DWORD;
FileName:String;
ExtraField:String;
FileComment:String;
end;
TEndOfCentralDir=packed record
EndOfCentralDirSignature:DWORD;
NumberOfThisDisk:Word;
NumberOfTheDiskWithTheStart:Word;
TotalNumberOfEntriesOnThisDisk:Word;
TotalNumberOfEntries:Word;
SizeOfTheCentralDirectory:DWORD;
OffsetOfStartOfCentralDirectory:DWORD;
ZipfileCommentLength:Word;
end;
TZipFile=class(TObject)
Files:array of TLocalFile;
CentralDirectory:array of TFileHeader;
EndOfCentralDirectory:TEndOfCentralDir;
ZipFileComment:String;
private
function GetUncompressed(I:Integer):String;
procedure SetUncompressed(I:Integer;const Value:String);
function GetDateTime(I:Integer):TDateTime;
procedure SetDateTime(I:Integer;const Value:TDateTime);
function GetCount:Integer;
function GetName(I:Integer):String;
procedure SetName(I:Integer;const Value:String);
public
procedure WriteFileToStream(Stream:TStream;FileName:String);
property Count:Integer read GetCount;
procedure AddFile(const Name:String;FAttribute:DWORD=0);
procedure SaveToFile(const FileName:String);
procedure SaveToStream(ZipFileStream:TStream);
procedure LoadFromFile(const FileName:String);
procedure LoadFromStream(const ZipFileStream:TStream);
property Data[I:Integer]:String read GetUncompressed write SetUncompressed;
property DateTime[I:Integer]:TDateTime read GetDateTime write SetDateTime;
property Name[I:Integer]:String read GetName write SetName;
end;
TSXPreloadedZipFile=class
public
FullPath:String;
FileName:String;
ZipFile:TZipFile;
SkinLibrary:Pointer;
constructor Create;
destructor Destroy; override;
end;
TSXPreloadedZipFileList=class
protected
FItem:TList;
function Get(const Index:Integer):TSXPreloadedZipFile;
procedure Put(const Index:Integer;const Item:TSXPreloadedZipFile);
function GetCount:Integer;
public
procedure Add(ZipFile:TSXPreloadedZipFile);
function GetZipFileIndex(const FileName:String):Integer;
procedure Delete(const Index:Integer);
procedure Clear;
constructor Create;
destructor Destroy; override;
property Item[const Index:Integer]:TSXPreloadedZipFile read Get write Put; default;
property Count:Integer read GetCount;
end;
EZipFileCRCError=class(Exception);
function ZipCRC32(const Data:String):Cardinal;
function PreloadZipFile(Stream:TStream;const FilePath:String;
SkinLibrary:Pointer):TZipFile;
function GetPreloadedZipFile(SkinLibrary:Pointer;const FilePath:String):TZipFile;
procedure DeletePreloadedZipFiles(SkinLibrary:Pointer);
function ExtractZipPath(var FilePath,ZipPath:String):Boolean;
var PreloadedZipFiles:TSXPreloadedZipFileList;
implementation
uses SXSkinUtils, SXSkinLibrary, SXZLibCompress;
{ TZipFile }
procedure TZipFile.SaveToFile(const FileName:String);
var ZipFileStream:TFileStream;
begin
ZipFileStream:=TFileStream.Create(FileName,fmCreate);
try
SaveToStream(ZipFileStream);
finally
ZipFileStream.Free;
end;
end;
procedure TZipFile.SaveToStream(ZipFileStream:TStream);
var I:Integer;
begin
for I:=0 to High(Files) do
with Files[i] do
begin
CentralDirectory[I].RelativeOffsetOfLocalHeader:=ZipFileStream.Position;
ZipFileStream.Write(LocalFileHeaderSignature,4);
if LocalFileHeaderSignature=$04034B50 then
begin
ZipFileStream.Write(CommonFileHeader,sizeof(CommonFileHeader));
ZipFileStream.Write(PChar(FileName)^,CommonFileHeader.FilenameLength);
ZipFileStream.Write(PChar(extrafield)^,CommonFileHeader.ExtraFieldLength);
ZipFileStream.Write(PChar(CompressedData)^,CommonFileHeader.CompressedSize);
end;
end;
EndOfCentralDirectory.OffsetOfStartOfCentralDirectory:=ZipFileStream.Position;
for I:=0 to High(CentralDirectory) do
with CentralDirectory[i] do
begin
ZipFileStream.Write(CentralFileHeaderSignature,4);
ZipFileStream.Write(VersionMadeBy,2);
ZipFileStream.Write(CommonFileHeader,sizeof(CommonFileHeader));
ZipFileStream.Write(FileCommentLength,2);
ZipFileStream.Write(DiskNumberStart,2);
ZipFileStream.Write(InternalFileAttributes,2);
ZipFileStream.Write(ExternalFileAttributes,4);
ZipFileStream.Write(RelativeOffsetOfLocalHeader,4);
ZipFileStream.Write(PChar(FileName)^,length(FileName));
ZipFileStream.Write(PChar(ExtraField)^,length(ExtraField));
ZipFileStream.Write(PChar(FileComment)^,length(FileComment));
end;
with EndOfCentralDirectory do
begin
EndOfCentralDirSignature:=$06054B50;
NumberOfThisDisk:=0;
NumberOfTheDiskWithTheStart:=0;
TotalNumberOfEntriesOnThisDisk:=High(Files)+1;
TotalNumberOfEntries:=High(Files)+1;
SizeOfTheCentralDirectory:=ZipFileStream.Position-OffsetOfStartOfCentralDirectory;
ZipfileCommentLength:=length(ZipFileComment);
end;
ZipFileStream.Write(EndOfCentralDirectory,sizeof(EndOfCentralDirectory));
ZipFileStream.Write(PChar(ZipFileComment)^,length(ZipFileComment));
end;
procedure TZipFile.LoadFromStream(const ZipFileStream:TStream);
var Signature:DWORD;
N:Integer;
begin
N:=0;
repeat
Signature:=0;
ZipFileStream.Read(Signature,4);
if ZipFileStream.Position=ZipFileStream.Size then exit;
until Signature=$04034B50;
repeat
if Signature=$04034B50 then
begin
Inc(N);
SetLength(Files,N);
SetLength(CentralDirectory,N);
with Files[N-1] do
begin
LocalFileHeaderSignature:=Signature;
ZipFileStream.Read(CommonFileHeader,sizeof(CommonFileHeader));
SetLength(FileName,CommonFileHeader.FilenameLength);
ZipFileStream.Read(PChar(FileName)^,CommonFileHeader.FilenameLength);
FileName:=StringReplace(FileName,'\','/',[rfReplaceAll]);
SetLength(ExtraField,CommonFileHeader.ExtraFieldLength);
ZipFileStream.Read(PChar(ExtraField)^,CommonFileHeader.ExtraFieldLength);
SetLength(CompressedData,CommonFileHeader.CompressedSize);
ZipFileStream.Read(PChar(CompressedData)^,CommonFileHeader.CompressedSize);
end;
end;
Signature:=0;
ZipFileStream.Read(Signature,4);
until Signature<>$04034B50;
N:=0;
repeat
if Signature=$02014B50 then
begin
Inc(N);
with CentralDirectory[N-1] do
begin
CentralFileHeaderSignature:=Signature;
ZipFileStream.Read(VersionMadeBy,2);
ZipFileStream.Read(CommonFileHeader,sizeof(CommonFileHeader));
ZipFileStream.Read(FileCommentLength,2);
ZipFileStream.Read(DiskNumberStart,2);
ZipFileStream.Read(InternalFileAttributes,2);
ZipFileStream.Read(ExternalFileAttributes,4);
ZipFileStream.Read(RelativeOffsetOfLocalHeader,4);
SetLength(FileName,CommonFileHeader.FilenameLength);
ZipFileStream.Read(PChar(FileName)^,CommonFileHeader.FileNameLength);
SetLength(ExtraField,CommonFileHeader.ExtraFieldLength);
ZipFileStream.Read(PChar(ExtraField)^,CommonFileHeader.ExtraFieldLength);
SetLength(FileComment,FileCommentLength);
ZipFileStream.Read(PChar(FileComment)^,FileCommentLength);
end;
end;
Signature:=0;
ZipFileStream.Read(Signature,4);
until Signature<>$02014B50;
if Signature=$06054B50 then
begin
EndOfCentralDirectory.EndOfCentralDirSignature:=Signature;
ZipFileStream.Read(EndOfCentralDirectory.NumberOfThisDisk,sizeof(EndOfCentralDirectory)-4);
SetLength(ZipFileComment,EndOfCentralDirectory.ZipfileCommentLength);
ZipFileStream.Read(PChar(ZipFileComment)^,EndOfCentralDirectory.ZipfileCommentLength);
end;
end;
procedure TZipFile.LoadFromFile(const FileName:String);
var ZipFileStream:TFileStream;
begin
ZipFileStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(ZipFileStream);
finally
ZipFileStream.Free;
end;
end;
procedure TZipFile.WriteFileToStream(Stream:TStream;FileName:String);
var A,B:Integer;
S:String;
begin
while (FileName<>'') and ((FileName[1]='/') or (FileName[1]='\')) do Delete(FileName,1,1);
FileName:=StringReplace(FileName,'\','/',[rfReplaceAll]);
B:=-1;
for A:=0 to High(Files) do
if SameText(Files[A].FileName,FileName) then
begin
B:=A;
break;
end;
if B<0 then exit;
S:=GetUncompressed(B);
Stream.Write(S[1],length(S));
end;
function TZipFile.GetUncompressed(I:Integer):String;
var Decompressor:TDecompressionStream;
UncompressedStream:TStringStream;
AHeader:String;
ReadBytes:Integer;
LoadedCrc32:DWORD;
begin
if (I<0) or (I>High(Files)) then
raise Exception.Create('Index out of range.');
AHeader:=Chr(120)+Chr(156);
if Files[I].CommonFileHeader.CompressionMethod=0 then //not compressed
begin
Result:=Files[I].CompressedData;
end else
begin
UncompressedStream:=TStringStream.Create(AHeader+Files[I].CompressedData);
try
Decompressor:=TDecompressionStream.Create(UncompressedStream);
try
SetLength(Result,Files[I].CommonFileHeader.UncompressedSize);
ReadBytes:=Decompressor.Read(PChar(Result)^,Files[I].CommonFileHeader.UncompressedSize);
if ReadBytes<>Integer(Files[I].CommonFileHeader.UncompressedSize) then Result:='';
finally
Decompressor.Free;
end;
finally
UncompressedStream.Free;
end;
LoadedCRC32:=ZipCRC32(Result);
if LoadedCRC32<>Files[I].CommonFileHeader.Crc32 then
raise EZipFileCRCError.CreateFmt('CRC Error in "%s".',[Files[I].FileName]);
end;
end;
procedure TZipFile.SetUncompressed(I:Integer;const Value:String);
var Compressor:TCompressionStream;
CompressedStream:TStringStream;
UseUncompressed:Boolean;
begin
if I>High(Files) then
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -