Delphi 2010/Delphi XE 的免费软件 ZIP 组件?

发布于 2024-08-11 09:40:06 字数 173 浏览 9 评论 0原文

你知道有什么免费的组件,兼容Delphi 2010XE来管理ZIP档案(实际上,只需要读取档案内容和提取文件)?

请不要使用测试版。

我考虑过 ComponentAce 的 ZipForge,但它仅免费供个人使用。不允许分发软件。

Do you know any free component, compatible with Delphi 2010 or XE to manage ZIP archives (actually, only reading archive contents and extracting files required)?

Please no betas.

I thought about ZipForge from ComponentAce, but it's free only for personal use. No software distribution allowed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

有木有妳兜一样 2024-08-18 09:40:06

您可以从以下网址获取 2010 年 TurboPower Abbrvia:
http://tpabbrevia.sourceforge.net/

You can get the TurboPower Abbrevia for 2010 from:
http://tpabbrevia.sourceforge.net/

梦冥 2024-08-18 09:40:06

如果你喜欢 7zip,你可以看看这个

you can take a look at this if you like 7zip

无悔心 2024-08-18 09:40:06

如果只需要解码(为Delphi 2007开发,尚未在Delphi 2010/XE下测试):

unit UnitZip;

interface

uses
  SysUtils, Classes;

type
  EZipException = class( Exception );

  TZipFileInfo = record
    LastModified:                      TDateTime;
    Crc32:                             Longword;
    CompressedSize:                    Longword;
    UncompressedSize:                  Longword;
  end;

  TZipFileReader = class
  private
    // Information about the memory mapped file
    FFileHandle:                       THandle;
    FFileMapping:                      THandle;
    FMappedAddress:                    Pointer;
    // Location of the ZIPfile in memory. Currently we only support memory mapped ZIPfiles without disk spanning.
    FStart:                            Pointer;
    FSize:                             Longword;
    // ZIP file contents
    FFilenames:                        TStrings;
    function    GetZipFileInfo         ( const FileName: AnsiString ): TZipFileInfo;
  public
    constructor Create                 ( const FileName: string; ZipStartOffset: Int64 = 0; Size: Longword = 0 ); overload;
    constructor Create                 ( const ResourceName, ResourceType: string; Instance: HMODULE = 0 ); overload;
    constructor Create                 ( Buffer: Pointer; Size: Longword ); overload;
    destructor  Destroy;               override;
    function    GetFile                ( const FileName: string ): TBytes; overload;
    function    GetFile                ( FileID: Integer ): TBytes; overload;
    property    FileNames:             TStrings read FFileNames;
    property    FileInfo               [ const FileName: AnsiString ]: TZipFileInfo read GetZipFileInfo;
  end;

implementation

uses
  ZLib, Windows;

const
  cResourceNotFound   = 'Resource not found: %s.%s.';
  cResourceNotLoaded  = 'Resource not loaded: %s.%s.';
  cCannotOpenFile     = 'Cannot open file %s: OS error: %d.';
  cCannotGetFileSize  = 'Cannot get file size of file %s: OS error: %d.';
  cCannotMapFile      = 'Cannot create file mapping of file %s: OS error: %d.';
  cZipFileTooSmall    = 'ZIP file is too small.';
  cZipFileFormatError = 'ZIP file is invalid.';
  cZipBufferInvalid   = 'ZIP memory buffer is invalid.';
  cUnsupportedMethod  = 'ZIP unsupported compression method: %d.';
  cFileNotFoundInZip  = 'File not found in ZIP content: %s';

// ZIP file format records.
// The generic zip file format is ( TLocalFileHeader; Name; Extra; compressed data )* ( TFileHeader; Name; Extra; Remark )* TLastHeader

type
  TFileInfo = packed record
    NeededVersion:                     Word;            // 20
    Flags:                             Word;            // 1=Text,4=extra present
    ZipMethod:                         Word;            // 0=stored 8=deflate
    LastModified:                      Longword;        // time in dos format or Unix Timestamp
    Crc32:                             Longword;
    CompressedSize:                    Longword;
    UncompressedSize:                  Longword;
    NameSize:                          Word;
    ExtraSize:                         Word;
  end;

  TFileHeader = packed record
    Signature:                         Longword;        // $02014b50 PK#1#2
    MadeBy:                            Word;            // Version number, 20
    FileInfo:                          TFileInfo;
    CommentSize:                       Word;            // 0
    FirstDiskNumber:                   Word;            // 0
    IntFileAttr:                       Word;            // 0 = binary; 1 = text
    ExtFileAttr:                       Longword;        // DOS file attributes (Archived=32)
    LocalFileHeaderHeadOff:            Longword;        // @TLocalFileHeader
  end;
  PFileHeader = ^TFileHeader;

  TLocalFileHeader = packed record
    Signature:                         Longword;        // $02014b50 PK#3#4
    FileInfo:                          TFileInfo;
  end;
  PLocalFileHeader = ^TLocalFileHeader;

  TLastHeader = packed record
    Signature:                         Longword;        // $02014b50 PK#5#6
    ThisDiskNumber:                    Word;
    CentralDirDisk:                    Word;
    ThisDiskFileCount:                 Word;
    TotalFileCount:                    Word;
    FileHeaderSize:                    Longword;
    FileHeaderOffset:                  Longword;
    CommentSize:                       Word;
  end;
  PLastHeader = ^TLastHeader;

const
  MagicLastHeader  = $06054b50;
  MagicLocalHeader = $04034b50;
  MagicFileHeader  = $02014b50;

type
  IntPtr = Longword; // NativeInt on Delphi2007 is an Int64 ??

{$if CompilerVersion < 19}
procedure SetAnsiString( var S: AnsiString; P: PAnsiChar; L: Integer ); inline;
begin
  SetString( S, P, L );
end;
{$ifend}

{ TZipFileReader }

constructor TZipFileReader.Create( const FileName: string; ZipStartOffset: Int64; Size: Longword );
begin
  // Open the file in question.
  FFileHandle := CreateFile( PChar( FileName ), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0 );
  if FFileHandle = INVALID_HANDLE_VALUE then raise EZipException.CreateFmt( cCannotOpenFile, [ Filename, GetLastError() ] );
  if Size = 0 then Size := GetFileSize( FFileHandle, nil );
  if Size = INVALID_FILE_SIZE then raise EZipException.CreateFmt( cCannotGetFileSize, [ Filename, GetLastError() ] );

  try
    // Create a file mapping of the file in question
    FFileMapping := CreateFileMapping( FFileHandle, nil, PAGE_READONLY, 0, 0, nil);
    if FFileMapping = 0 then raise EZipException.CreateFmt( cCannotMapFile, [ Filename, GetLastError() ] );

    try
      // Get the file mapped in memory (NOTE: The offset needs to be on the  memory allocation granularity of the system)
      // Hence we assign it it's own pointer -> todo rounding etc.
      FMappedAddress := MapViewOfFile( FFileMapping, FILE_MAP_READ, Int64Rec( ZipStartOffset ).Hi, Int64Rec( ZipStartOffset ).Lo, Size );
      if not Assigned( FMappedAddress ) then EZipException.CreateFmt( cCannotMapFile, [ Filename, GetLastError() ] );
      Create( FMappedAddress, Size );
    except
      CloseHandle( FFileMapping );
      FFileMapping := 0;
      raise;
    end;
  except
    CloseHandle( FFileHandle );
    FFileHandle := 0;
    raise;
  end;
end;

constructor TZipFileReader.Create( const ResourceName, ResourceType: string; Instance: HMODULE );
var
  Resource: HRSRC;
  Global:   HGLOBAL;
begin
  Resource := FindResource( Instance, PChar( ResourceName ), PChar( ResourceType ) );
  if Resource = 0 then raise EZipException.CreateFmt( cResourceNotFound, [ ResourceName, ResourceType ] );
  Global := LoadResource( Instance, Resource );
  if Global = 0 then raise EZipException.CreateFmt( cResourceNotLoaded, [ ResourceName, ResourceType ] );
  Create( LockResource( Global ), SizeofResource( HInstance, Resource ) );
  // Note: kb57808: SizeofResource() returns the resource size rounded up to the alignment size.
end;

constructor TZipFileReader.Create( Buffer: Pointer; Size: Longword );
var
  LastHeader: PLastHeader;
  FileHeader: PFileHeader;
  i, Off:     Longword;
  Name:       AnsiString;
begin
  // Note the location.
  FStart := Buffer;
  FSize  := Size;

  // Some sanity checks.
  if FSize < sizeof( TLocalFileHeader ) + sizeof( TFileHeader ) + sizeof( TLastHeader ) then raise EZipException.Create( cZipFileTooSmall );
  if IsBadReadPtr( Buffer, Size ) then raise EZipException.Create( cZipBufferInvalid );
  if PLongword( Buffer )^ <> MagicLocalHeader then raise EZipException.Create( cZipFileFormatError );

  // Find the last header. Due to the alignment of SizeofResource, we need o search for it.
  LastHeader := Pointer( IntPtr( Buffer ) + Size - sizeof( TLastHeader ) );
  for i := 0 to 31 do begin
    if LastHeader^.Signature = MagicLastHeader then Break;
    Dec( IntPtr( LastHeader ) );
  end;
  if LastHeader^.Signature <> MagicLastHeader then raise EZipException.Create( cZipFileFormatError );

  FFilenames := TStringList.Create();

  Off := LastHeader^.FileHeaderOffset;
  for i := 0 to LastHeader^.TotalFileCount - 1 do begin
    // Get header
    if Off + sizeof( TFileHeader ) >= Size then raise EZipException.Create( cZipFileFormatError );
    FileHeader := Pointer( IntPtr( Buffer ) + Off );
    Inc( Off, sizeof( TFileHeader ) );
    if FileHeader^.Signature <> MagicFileHeader then raise EZipException.Create( cZipFileFormatError );

    // Get filename
    if Off + FileHeader^.FileInfo.NameSize + FileHeader^.FileInfo.ExtraSize >= Size then raise EZipException.Create( cZipFileFormatError );
    SetAnsiString( Name, Pointer( IntPtr( Buffer ) + Off ), FileHeader^.FileInfo.NameSize );
    Inc( Off, FileHeader^.FileInfo.NameSize + FileHeader^.FileInfo.ExtraSize );

    // Save filename and offset into ZIPfile where it can be found.
    FFileNames.AddObject( Name, Pointer( FileHeader^.LocalFileHeaderHeadOff ) );
  end;
  // For quick access.
  TStringList( FFilenames ).Sorted := True;

end;

destructor TZipFileReader.Destroy;
begin
  if Assigned( FMappedAddress ) then UnmapViewOfFile( FMappedAddress );
  if FFileMapping <> 0 then CloseHandle( FFileMapping );
  if FFileHandle  <> 0 then CloseHandle( FFileHandle  );
  inherited Destroy;
end;

function TZipFileReader.GetFile( const FileName: string ): TBytes;
var
  ID: Integer;
begin
  // Convert filename in FileID and access by ID.
  ID := FFilenames.IndexOf( FileName );
  if ID < 0 then raise EZipException.CreateFmt( cFileNotFoundInZip, [ FileName ] );
  Result := GetFile( ID );
end;

function TZipFileReader.GetFile( FileID: Integer ): TBytes;
var
  Off:   Longword;
  Local: PLocalFileHeader;
  ZRec:  TZStreamRec;
const
  ZLibHeader: array [ 0..1 ] of Byte = ( $78, $01 ); // Deflate 32KB window size no preset dictionary.
begin
  // Sanity check
  if ( FileID < 0 ) or ( FileID >= FFilenames.Count ) then raise EZipException.CreateFmt( 'Invalid File ID: %d', [ FileID ] );

  // Get the file header and perform sanity check
  Off := Longword( FFilenames.Objects[ FileID ] );
  if Off + sizeof( TLocalFileHeader ) >= FSize then raise EZipException.Create( cZipFileFormatError );
  Local := Pointer( IntPtr( FStart ) + Off );
  if Local^.Signature <> MagicLocalHeader then raise EZipException.Create( cZipFileFormatError );
  Inc( Off, sizeof( TLocalFileHeader ) + Local^.FileInfo.NameSize + Local^.FileInfo.ExtraSize );
  if Off + Local^.FileInfo.CompressedSize >= FSize then raise EZipException.Create( cZipFileFormatError );
  // note: should we check the name again?

  SetLength( Result, Local^.FileInfo.UncompressedSize );
  if Length( Result ) > 0 then case Local^.FileInfo.ZipMethod of
    0:   begin // STORED
           if Local^.FileInfo.CompressedSize <> Local^.FileInfo.UncompressedSize then raise EZipException.Create( cZipFileFormatError );
           Move( Pointer( IntPtr( FStart ) + Off )^, Result[ 0 ], Local^.FileInfo.UncompressedSize );
         end;
    8:   begin // DEFLATE
           ZeroMemory( @ZRec, sizeof( ZRec ) );
           ZRec.next_in   := @ZLibHeader;
           ZRec.avail_in  := sizeof( ZLibHeader );
           ZRec.total_in  := sizeof( ZLibHeader ) + Local^.FileInfo.CompressedSize;
           ZRec.next_out  := @Result[ 0 ];
           ZRec.avail_out := Local^.FileInfo.UncompressedSize;
           ZRec.total_out := Local^.FileInfo.UncompressedSize;
           ZRec.zalloc    := zlibAllocMem;
           ZRec.zfree     := zlibFreeMem;
           if inflateInit_( ZRec, zlib_Version, sizeof( ZRec ) ) <> 0 then raise EZipException.Create( cZipFileFormatError );
           try
             if not( inflate( ZRec, Z_FULL_FLUSH ) in [ Z_OK, Z_STREAM_END ] ) then raise EZipException.Create( cZipFileFormatError );
             ZRec.next_in   := Pointer( IntPtr( FStart ) + Off );
             ZRec.avail_in  := Local^.FileInfo.CompressedSize;
             if not( inflate( ZRec, Z_FINISH ) in [ Z_OK, Z_STREAM_END ] ) then raise EZipException.Create( cZipFileFormatError );
           finally
             inflateEnd( ZRec );
           end;
         end;
    else raise EZipException.CreateFmt( cUnsupportedMethod, [ Local^.FileInfo.ZipMethod ] );
  end;

  // todo: CRC32 sanity check if requested.
end;

function TZipFileReader.GetZipFileInfo( const FileName: AnsiString ): TZipFileInfo;
var
  FileID: Integer;
  Off:    Longword;
  Local:  PLocalFileHeader;
begin
  // Get the correct file ID
  FileID := FFilenames.IndexOf( FileName );
  if FileID < 0 then raise EZipException.CreateFmt( cFileNotFoundInZip, [ FileName ] );

  // Get the file header and perform sanity check
  Off := Longword( FFilenames.Objects[ FileID ] );
  if Off + sizeof( TLocalFileHeader ) >= FSize then raise EZipException.Create( cZipFileFormatError );
  Local := Pointer( IntPtr( FStart ) + Off );
  if Local^.Signature <> MagicLocalHeader then raise EZipException.Create( cZipFileFormatError );
  Inc( Off, sizeof( TLocalFileHeader ) + Local^.FileInfo.NameSize + Local^.FileInfo.ExtraSize );
  if Off + Local^.FileInfo.CompressedSize >= FSize then raise EZipException.Create( cZipFileFormatError );

  // Return requested data.
  Result.LastModified     := Local^.FileInfo.LastModified;
  Result.Crc32            := Local^.FileInfo.Crc32;
  Result.CompressedSize   := Local^.FileInfo.CompressedSize;
  Result.UncompressedSize := Local^.FileInfo.UncompressedSize;
end;

end.

If you only need decoding (developed for Delphi 2007, not yet tested under Delphi 2010/XE):

unit UnitZip;

interface

uses
  SysUtils, Classes;

type
  EZipException = class( Exception );

  TZipFileInfo = record
    LastModified:                      TDateTime;
    Crc32:                             Longword;
    CompressedSize:                    Longword;
    UncompressedSize:                  Longword;
  end;

  TZipFileReader = class
  private
    // Information about the memory mapped file
    FFileHandle:                       THandle;
    FFileMapping:                      THandle;
    FMappedAddress:                    Pointer;
    // Location of the ZIPfile in memory. Currently we only support memory mapped ZIPfiles without disk spanning.
    FStart:                            Pointer;
    FSize:                             Longword;
    // ZIP file contents
    FFilenames:                        TStrings;
    function    GetZipFileInfo         ( const FileName: AnsiString ): TZipFileInfo;
  public
    constructor Create                 ( const FileName: string; ZipStartOffset: Int64 = 0; Size: Longword = 0 ); overload;
    constructor Create                 ( const ResourceName, ResourceType: string; Instance: HMODULE = 0 ); overload;
    constructor Create                 ( Buffer: Pointer; Size: Longword ); overload;
    destructor  Destroy;               override;
    function    GetFile                ( const FileName: string ): TBytes; overload;
    function    GetFile                ( FileID: Integer ): TBytes; overload;
    property    FileNames:             TStrings read FFileNames;
    property    FileInfo               [ const FileName: AnsiString ]: TZipFileInfo read GetZipFileInfo;
  end;

implementation

uses
  ZLib, Windows;

const
  cResourceNotFound   = 'Resource not found: %s.%s.';
  cResourceNotLoaded  = 'Resource not loaded: %s.%s.';
  cCannotOpenFile     = 'Cannot open file %s: OS error: %d.';
  cCannotGetFileSize  = 'Cannot get file size of file %s: OS error: %d.';
  cCannotMapFile      = 'Cannot create file mapping of file %s: OS error: %d.';
  cZipFileTooSmall    = 'ZIP file is too small.';
  cZipFileFormatError = 'ZIP file is invalid.';
  cZipBufferInvalid   = 'ZIP memory buffer is invalid.';
  cUnsupportedMethod  = 'ZIP unsupported compression method: %d.';
  cFileNotFoundInZip  = 'File not found in ZIP content: %s';

// ZIP file format records.
// The generic zip file format is ( TLocalFileHeader; Name; Extra; compressed data )* ( TFileHeader; Name; Extra; Remark )* TLastHeader

type
  TFileInfo = packed record
    NeededVersion:                     Word;            // 20
    Flags:                             Word;            // 1=Text,4=extra present
    ZipMethod:                         Word;            // 0=stored 8=deflate
    LastModified:                      Longword;        // time in dos format or Unix Timestamp
    Crc32:                             Longword;
    CompressedSize:                    Longword;
    UncompressedSize:                  Longword;
    NameSize:                          Word;
    ExtraSize:                         Word;
  end;

  TFileHeader = packed record
    Signature:                         Longword;        // $02014b50 PK#1#2
    MadeBy:                            Word;            // Version number, 20
    FileInfo:                          TFileInfo;
    CommentSize:                       Word;            // 0
    FirstDiskNumber:                   Word;            // 0
    IntFileAttr:                       Word;            // 0 = binary; 1 = text
    ExtFileAttr:                       Longword;        // DOS file attributes (Archived=32)
    LocalFileHeaderHeadOff:            Longword;        // @TLocalFileHeader
  end;
  PFileHeader = ^TFileHeader;

  TLocalFileHeader = packed record
    Signature:                         Longword;        // $02014b50 PK#3#4
    FileInfo:                          TFileInfo;
  end;
  PLocalFileHeader = ^TLocalFileHeader;

  TLastHeader = packed record
    Signature:                         Longword;        // $02014b50 PK#5#6
    ThisDiskNumber:                    Word;
    CentralDirDisk:                    Word;
    ThisDiskFileCount:                 Word;
    TotalFileCount:                    Word;
    FileHeaderSize:                    Longword;
    FileHeaderOffset:                  Longword;
    CommentSize:                       Word;
  end;
  PLastHeader = ^TLastHeader;

const
  MagicLastHeader  = $06054b50;
  MagicLocalHeader = $04034b50;
  MagicFileHeader  = $02014b50;

type
  IntPtr = Longword; // NativeInt on Delphi2007 is an Int64 ??

{$if CompilerVersion < 19}
procedure SetAnsiString( var S: AnsiString; P: PAnsiChar; L: Integer ); inline;
begin
  SetString( S, P, L );
end;
{$ifend}

{ TZipFileReader }

constructor TZipFileReader.Create( const FileName: string; ZipStartOffset: Int64; Size: Longword );
begin
  // Open the file in question.
  FFileHandle := CreateFile( PChar( FileName ), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0 );
  if FFileHandle = INVALID_HANDLE_VALUE then raise EZipException.CreateFmt( cCannotOpenFile, [ Filename, GetLastError() ] );
  if Size = 0 then Size := GetFileSize( FFileHandle, nil );
  if Size = INVALID_FILE_SIZE then raise EZipException.CreateFmt( cCannotGetFileSize, [ Filename, GetLastError() ] );

  try
    // Create a file mapping of the file in question
    FFileMapping := CreateFileMapping( FFileHandle, nil, PAGE_READONLY, 0, 0, nil);
    if FFileMapping = 0 then raise EZipException.CreateFmt( cCannotMapFile, [ Filename, GetLastError() ] );

    try
      // Get the file mapped in memory (NOTE: The offset needs to be on the  memory allocation granularity of the system)
      // Hence we assign it it's own pointer -> todo rounding etc.
      FMappedAddress := MapViewOfFile( FFileMapping, FILE_MAP_READ, Int64Rec( ZipStartOffset ).Hi, Int64Rec( ZipStartOffset ).Lo, Size );
      if not Assigned( FMappedAddress ) then EZipException.CreateFmt( cCannotMapFile, [ Filename, GetLastError() ] );
      Create( FMappedAddress, Size );
    except
      CloseHandle( FFileMapping );
      FFileMapping := 0;
      raise;
    end;
  except
    CloseHandle( FFileHandle );
    FFileHandle := 0;
    raise;
  end;
end;

constructor TZipFileReader.Create( const ResourceName, ResourceType: string; Instance: HMODULE );
var
  Resource: HRSRC;
  Global:   HGLOBAL;
begin
  Resource := FindResource( Instance, PChar( ResourceName ), PChar( ResourceType ) );
  if Resource = 0 then raise EZipException.CreateFmt( cResourceNotFound, [ ResourceName, ResourceType ] );
  Global := LoadResource( Instance, Resource );
  if Global = 0 then raise EZipException.CreateFmt( cResourceNotLoaded, [ ResourceName, ResourceType ] );
  Create( LockResource( Global ), SizeofResource( HInstance, Resource ) );
  // Note: kb57808: SizeofResource() returns the resource size rounded up to the alignment size.
end;

constructor TZipFileReader.Create( Buffer: Pointer; Size: Longword );
var
  LastHeader: PLastHeader;
  FileHeader: PFileHeader;
  i, Off:     Longword;
  Name:       AnsiString;
begin
  // Note the location.
  FStart := Buffer;
  FSize  := Size;

  // Some sanity checks.
  if FSize < sizeof( TLocalFileHeader ) + sizeof( TFileHeader ) + sizeof( TLastHeader ) then raise EZipException.Create( cZipFileTooSmall );
  if IsBadReadPtr( Buffer, Size ) then raise EZipException.Create( cZipBufferInvalid );
  if PLongword( Buffer )^ <> MagicLocalHeader then raise EZipException.Create( cZipFileFormatError );

  // Find the last header. Due to the alignment of SizeofResource, we need o search for it.
  LastHeader := Pointer( IntPtr( Buffer ) + Size - sizeof( TLastHeader ) );
  for i := 0 to 31 do begin
    if LastHeader^.Signature = MagicLastHeader then Break;
    Dec( IntPtr( LastHeader ) );
  end;
  if LastHeader^.Signature <> MagicLastHeader then raise EZipException.Create( cZipFileFormatError );

  FFilenames := TStringList.Create();

  Off := LastHeader^.FileHeaderOffset;
  for i := 0 to LastHeader^.TotalFileCount - 1 do begin
    // Get header
    if Off + sizeof( TFileHeader ) >= Size then raise EZipException.Create( cZipFileFormatError );
    FileHeader := Pointer( IntPtr( Buffer ) + Off );
    Inc( Off, sizeof( TFileHeader ) );
    if FileHeader^.Signature <> MagicFileHeader then raise EZipException.Create( cZipFileFormatError );

    // Get filename
    if Off + FileHeader^.FileInfo.NameSize + FileHeader^.FileInfo.ExtraSize >= Size then raise EZipException.Create( cZipFileFormatError );
    SetAnsiString( Name, Pointer( IntPtr( Buffer ) + Off ), FileHeader^.FileInfo.NameSize );
    Inc( Off, FileHeader^.FileInfo.NameSize + FileHeader^.FileInfo.ExtraSize );

    // Save filename and offset into ZIPfile where it can be found.
    FFileNames.AddObject( Name, Pointer( FileHeader^.LocalFileHeaderHeadOff ) );
  end;
  // For quick access.
  TStringList( FFilenames ).Sorted := True;

end;

destructor TZipFileReader.Destroy;
begin
  if Assigned( FMappedAddress ) then UnmapViewOfFile( FMappedAddress );
  if FFileMapping <> 0 then CloseHandle( FFileMapping );
  if FFileHandle  <> 0 then CloseHandle( FFileHandle  );
  inherited Destroy;
end;

function TZipFileReader.GetFile( const FileName: string ): TBytes;
var
  ID: Integer;
begin
  // Convert filename in FileID and access by ID.
  ID := FFilenames.IndexOf( FileName );
  if ID < 0 then raise EZipException.CreateFmt( cFileNotFoundInZip, [ FileName ] );
  Result := GetFile( ID );
end;

function TZipFileReader.GetFile( FileID: Integer ): TBytes;
var
  Off:   Longword;
  Local: PLocalFileHeader;
  ZRec:  TZStreamRec;
const
  ZLibHeader: array [ 0..1 ] of Byte = ( $78, $01 ); // Deflate 32KB window size no preset dictionary.
begin
  // Sanity check
  if ( FileID < 0 ) or ( FileID >= FFilenames.Count ) then raise EZipException.CreateFmt( 'Invalid File ID: %d', [ FileID ] );

  // Get the file header and perform sanity check
  Off := Longword( FFilenames.Objects[ FileID ] );
  if Off + sizeof( TLocalFileHeader ) >= FSize then raise EZipException.Create( cZipFileFormatError );
  Local := Pointer( IntPtr( FStart ) + Off );
  if Local^.Signature <> MagicLocalHeader then raise EZipException.Create( cZipFileFormatError );
  Inc( Off, sizeof( TLocalFileHeader ) + Local^.FileInfo.NameSize + Local^.FileInfo.ExtraSize );
  if Off + Local^.FileInfo.CompressedSize >= FSize then raise EZipException.Create( cZipFileFormatError );
  // note: should we check the name again?

  SetLength( Result, Local^.FileInfo.UncompressedSize );
  if Length( Result ) > 0 then case Local^.FileInfo.ZipMethod of
    0:   begin // STORED
           if Local^.FileInfo.CompressedSize <> Local^.FileInfo.UncompressedSize then raise EZipException.Create( cZipFileFormatError );
           Move( Pointer( IntPtr( FStart ) + Off )^, Result[ 0 ], Local^.FileInfo.UncompressedSize );
         end;
    8:   begin // DEFLATE
           ZeroMemory( @ZRec, sizeof( ZRec ) );
           ZRec.next_in   := @ZLibHeader;
           ZRec.avail_in  := sizeof( ZLibHeader );
           ZRec.total_in  := sizeof( ZLibHeader ) + Local^.FileInfo.CompressedSize;
           ZRec.next_out  := @Result[ 0 ];
           ZRec.avail_out := Local^.FileInfo.UncompressedSize;
           ZRec.total_out := Local^.FileInfo.UncompressedSize;
           ZRec.zalloc    := zlibAllocMem;
           ZRec.zfree     := zlibFreeMem;
           if inflateInit_( ZRec, zlib_Version, sizeof( ZRec ) ) <> 0 then raise EZipException.Create( cZipFileFormatError );
           try
             if not( inflate( ZRec, Z_FULL_FLUSH ) in [ Z_OK, Z_STREAM_END ] ) then raise EZipException.Create( cZipFileFormatError );
             ZRec.next_in   := Pointer( IntPtr( FStart ) + Off );
             ZRec.avail_in  := Local^.FileInfo.CompressedSize;
             if not( inflate( ZRec, Z_FINISH ) in [ Z_OK, Z_STREAM_END ] ) then raise EZipException.Create( cZipFileFormatError );
           finally
             inflateEnd( ZRec );
           end;
         end;
    else raise EZipException.CreateFmt( cUnsupportedMethod, [ Local^.FileInfo.ZipMethod ] );
  end;

  // todo: CRC32 sanity check if requested.
end;

function TZipFileReader.GetZipFileInfo( const FileName: AnsiString ): TZipFileInfo;
var
  FileID: Integer;
  Off:    Longword;
  Local:  PLocalFileHeader;
begin
  // Get the correct file ID
  FileID := FFilenames.IndexOf( FileName );
  if FileID < 0 then raise EZipException.CreateFmt( cFileNotFoundInZip, [ FileName ] );

  // Get the file header and perform sanity check
  Off := Longword( FFilenames.Objects[ FileID ] );
  if Off + sizeof( TLocalFileHeader ) >= FSize then raise EZipException.Create( cZipFileFormatError );
  Local := Pointer( IntPtr( FStart ) + Off );
  if Local^.Signature <> MagicLocalHeader then raise EZipException.Create( cZipFileFormatError );
  Inc( Off, sizeof( TLocalFileHeader ) + Local^.FileInfo.NameSize + Local^.FileInfo.ExtraSize );
  if Off + Local^.FileInfo.CompressedSize >= FSize then raise EZipException.Create( cZipFileFormatError );

  // Return requested data.
  Result.LastModified     := Local^.FileInfo.LastModified;
  Result.Crc32            := Local^.FileInfo.Crc32;
  Result.CompressedSize   := Local^.FileInfo.CompressedSize;
  Result.UncompressedSize := Local^.FileInfo.UncompressedSize;
end;

end.
非要怀念 2024-08-18 09:40:06

看一下这个开源SynZip 单元。它的解压速度比 Delphi 附带的默认单元更快,并且会生成更小的 exe(crc 表在启动时创建)。

不需要外部 dll。

我只是做了一些更改来处理 Zip 内容中的 Unicode 文件名,不仅是 Win-Ansi 字符集,还包括任何 Unicode 字符。欢迎反馈。

Take a look at this OpenSource SynZip unit. It's even faster for decompression than the default unit shipped with Delphi, and it will generate a smaller exe (crc tables are created at startup).

No external dll is needed.

I just made some changes to handle Unicode file names inside Zip content, not only Win-Ansi charset but any Unicode chars. Feedback is welcome.

隐诗 2024-08-18 09:40:06

我喜欢 WinZip 兼容的 Delphi TZipMaster,可以在这里找到:http://www.delphizip.org/

TZipMaster 是一个非可视化的 VCL 包装器
由 ChrisVleghert 创建和
EricW.Engler 的免费软件 Zip
并解压缩 DLL。

这些 DLL 基于 InfoZip
官方免费软件 Zip/Unzip 源
代码,但不等于
InfoZip 的 DLL。 InfoZip 源代码
代码已被修改以增强
它们的易用性、功能和
可以灵活地与 Delphi 一起使用
C++ 生成器。

另外,这个问题之前已经讨论过 在 Stack Overflow 上,这可能会为您提供一些其他解决方案。

I like the WinZip compatible TZipMaster for Delphi, available here: http://www.delphizip.org/

TZipMaster is a non-visual VCL wrapper
created by ChrisVleghert and
EricW.Engler for their freeware Zip
and Unzip DLLs.

Those DLLs are based on the InfoZip
Official Freeware Zip/Unzip source
code, but are NOT equivalent to
InfoZip's DLLs. The InfoZip source
code has been modified to enhance
their ease-of-use, power, and
flexibility for use with Delphi and
C++ Builder.

Also, this question has been covered before on Stack Overflow, which may yield some other solutions for you.

逆夏时光 2024-08-18 09:40:06

如果在您的项目中分发 ActiveX DLL 对您来说不是问题,那么 Chilkat Zip (http://www.chilkatsoft.com/zip-activex.asp) 似乎可以解决问题。 Delphi 示例在这里:http://www.example-code.com/delphi/zip。 ASP

If distributing an ActiveX DLL with your project is not a problem for you, then Chilkat Zip (http://www.chilkatsoft.com/zip-activex.asp) seems to do the trick. Delphi examples are here: http://www.example-code.com/delphi/zip.asp

等风也等你 2024-08-18 09:40:06

DotNetZip 是一个托管代码 (.NET) 库,它公开 COM 接口。

免费。
开源
MS-PL 已获得许可。

DotNetZip is a managed code (.NET) library, that exposes a COM interface.

Free.
Open source
MS-PL licensed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文